WPF - bindowanie grup controlek

0

Pisze sobie aplikacje i powiedzmy ze mam cos takiego
Przyciski te robią to samo tylko na textboxach tylko pod soba, przez co mam troche copy/paste i chciałbym to zmienić ale za bardzo nie wiem jak, bo mam problem z MVVM :/

1.png

 public class Client : INotifyPropertyChanged
    {
        private string _firstName;
        private string _lastName;

        public string FirstName
        {
            get
            {
                return _firstName;
            }
            set
            {
                _firstName = value;
                OnPropertyChanged("FirstName");
            }
        }

        public string LastName
        {
            get
            {
                return _lastName;
                
            }
            set
            {
                _lastName = value;
                OnPropertyChanged("LastName");
            }
        }


        public static Client GetClient()
        {
            var client = new Client()
            {
                FirstName = "Tom",
                LastName = "Male"
            };
            return client;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    } 
0

Kod tu nic nie mówi, ale na podstawie obrazka sugeruję zamknąć przycisk i jego textboxy w osobnej kontrolce i w oknie MainWindow umieścić dwie takie kontrolki. Kontrolka powinna udostępniać właściwości (ale nie zwykłe, tylko DependencyProperty) do danych, na które masz Binding (zawartość textboxów, akcja na kliknięcie przycisku, tekst na przycisku - cokolwiek tam potrzebujesz). Wtedy w MainWindow każdej kontrolce w tych DependencyProperty ustawiasz Binding z odpowiednimi dla niej danymi z ViewModelu.

Przy okazji - jeśli zamierzasz pisać coś więcej w MVVM, polecam bibliotekę MVVMLight. Wtedy np. nie trzeba pisać w każdym ViewModelu implementacji INotifyPropertyChanged, tylko dziedziczyć z klasy ViewModelBase.

0

Czyli mam stworzyć nowy UserControl i to dodać do MainWindow? Dopiero zaczynam z MVVM i za bardzo nie ogarniam :P
Obczaje MVVMLight

Reszta kodu:

 public partial class MainWindow
{

    private DirectoryCopy _directoryCopy;
    private ServiceSwitcher _serviceSwitcher;
    private FileSourceResearcher _fileSourceResearcher;
    private Client _client;
    private const string ConfigFilePath = "\\Data.Service.Host.exe.Config";
    private const string IpXmlExpresion = "//client//endpoint[@name = \"IClientsService\"]/@address";
    private const string ConnectionStringXmlExpresion = "//connectionStrings/add[1]/@connectionString";
    private const string WebpageUriXmlExpresion = "//appSettings/add[@key = \"WebpageUri\"]/@value";

    public MainWindow()
    {
        InitializeComponent();
    }

    private void buttonUpdate_Click(object sender, RoutedEventArgs e)
    {
        _serviceSwitcher = new ServiceSwitcher();
        _directoryCopy = new DirectoryCopy();

        if (StopServiceCheckBox.IsChecked != null && StopServiceCheckBox.IsChecked.Value)
            {
                _serviceSwitcher.StopService(_client.Name);
                StartServiceButton.IsEnabled = true;
            }

        ReplaceConnectionStringAndIp();
        _directoryCopy.CopyDirectory(TextBoxNew.Text, TextBoxOld.Text, true);
        LogsTextBox.AppendText("\nUpdate - success");
    }

    private void ReplaceConnectionStringAndIp()
    {
        string readText = File.ReadAllText(TextBoxNew.Text + ConfigFilePath);
        readText = readText.Replace(NewIpLabel.Content.ToString(), OldIpLabel.Content.ToString());
        readText = readText.Replace(NewWebpageUriLabel.Content.ToString(), OldWebpageUriLabel.Content.ToString());
        readText = readText.Replace(NewConnectionStringTextBox.Text, OldConnectionStringTextBox.Text);
        File.WriteAllText(TextBoxNew.Text + ConfigFilePath, readText);

    }

    private void button_ClickOld(object sender, RoutedEventArgs e)
    {
        SelectVerifyAndLog(TextBoxOld, UpdateOldLabel);
    }
    private void button_ClickNew(object sender, RoutedEventArgs e)
    {
        SelectVerifyAndLog(TextBoxNew, UpdateNewLabel);
    }

    void SelectVerifyAndLog(TextBox textBox, Action updateLabel)
    {
        textBox.Text = SelectCatalog();
        if (File.Exists(textBox.Text + ConfigFilePath))
        {
            LogsTextBox.AppendText("\nCorrect folder selected - success");
            GetClientProperty(textBox.Text);
            updateLabel();
        }
        else
        {
           if(textBox.Text != "") LogsTextBox.AppendText("\nWrong folder selected - Config file doesn't exist");
        }
    }


    private string SelectCatalog()
    {
        var folderDialog = new FolderBrowserDialog();

        var result = folderDialog.ShowDialog();
        if (result.ToString() == "OK")
        {
            return folderDialog.SelectedPath;
        }
        return "";
    }
    private void GetClientProperty(string folderDialog)
    {
        var path = folderDialog + ConfigFilePath;

        _fileSourceResearcher = new FileSourceResearcher();

            _client = new Client
            {
                Name = GetFolderName(path),
                Ip = GetIpFromString(_fileSourceResearcher.Search(path, IpXmlExpresion)),
                ConnectionString = _fileSourceResearcher.Search(path, ConnectionStringXmlExpresion),
                WebpageUri = _fileSourceResearcher.Search(path, WebpageUriXmlExpresion)
            };
        LogsTextBox.AppendText("\nDownload version properties - success");
    }

    private void UpdateNewLabel()
    {
        NewNameLabel.Content = _client.Name;
        NewIpLabel.Content = _client.Ip;
        NewConnectionStringTextBox.Text = _client.ConnectionString;
        NewWebpageUriLabel.Content = _client.WebpageUri;
    }
    private void UpdateOldLabel()
    {
        OldNameLabel.Content = _client.Name;
        OldIpLabel.Content = _client.Ip;
        OldConnectionStringTextBox.Text = _client.ConnectionString;
        OldWebpageUriLabel.Content = _client.WebpageUri;
    }

    private static string GetIpFromString(string value)
    {
        var result = "";
        var ifThreeBreak = 0;
        foreach (var ipString in value)
        {
            if (ipString == '/') ifThreeBreak++;
            if (ifThreeBreak == 2 && ipString != '/') result += ipString;
            if (ifThreeBreak == 3) break;
        }
        return result;
    }

    public string GetFolderName(string path)
    {
        var name = "";
        var ifTwoBreak = 0;
        var indexOfNameStart = 0;
        var indexOfNameEnd = 0;
        for (int i = path.Length-1; i >= 0; i--)
        {
            if (path[i] == '\\')ifTwoBreak++;
            if (ifTwoBreak == 1)
            {
                indexOfNameEnd = i;
                ifTwoBreak++;
            } 
            if (ifTwoBreak == 3)
            { 
                indexOfNameStart = i + 1;
                break;
            }
        }

        for (var i = indexOfNameStart; i < indexOfNameEnd; i++)
        {
            name += path[i];
        }
        return name;
    }

    private void button_ClickNewConnection(object sender, RoutedEventArgs e)
    {
        MessageBox.Show(NewConnectionStringTextBox.Text);
    }

    private void button_ClickOldConnection(object sender, RoutedEventArgs e)
    {
        MessageBox.Show(OldConnectionStringTextBox.Text);
    }

    private void buttonStartService_Click(object sender, RoutedEventArgs e)
    {
        _serviceSwitcher.StartService(_client.Name);
    }
} 
public class Client : INotifyPropertyChanged
{
    private string _name;
    private string _ip;
    private string _connectionString;
    private string _webpageUri;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged("Name");
        }
    }

    public string Ip
    {
        get { return _ip; }
        set
        {
            _ip = value;
            OnPropertyChanged("Ip");
        }
    }

    public string ConnectionString
    {
        get { return _connectionString; }
        set
        {
            _connectionString = value;
            OnPropertyChanged("ConnectionString");
        }
    }

    public string WebpageUri
    {
        get { return _webpageUri; }
        set
        {
            _webpageUri = value; 
            OnPropertyChanged("WebpageUri");
        }
    }

    public static Client GetClient()
    {
        var client = new Client()
        {
            _name = "Name",
            _connectionString = "ConnectionString",
            _ip = "Ip",
            _webpageUri = "WebpageUri"
        };
        return client;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
} 
 <Window x:Class="EasyUpdater.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    mc:Ignorable="d"
    Title="EasyUpdater" Height="550" Width="525" ResizeMode="NoResize">
<Grid Background="Linen">
    <Button x:Name="ButtonOld" Content="..." HorizontalAlignment="Left" Margin="149,35,0,0" VerticalAlignment="Top" Width="25" Click="button_ClickOld"/>
    <TextBox x:Name="TextBoxOld" HorizontalAlignment="Left" Height="23" Margin="24,35,0,0" Text="" VerticalAlignment="Top" Width="120" IsReadOnly="True"/>
    <Button x:Name="ButtonNew" Content="..." HorizontalAlignment="Left" Margin="447,35,0,0" VerticalAlignment="Top" Width="25" Click="button_ClickNew"/>
    <TextBox x:Name="TextBoxNew" HorizontalAlignment="Left" Height="23" Margin="322,35,0,0" Text="" VerticalAlignment="Top" Width="120" IsReadOnly="True"/>
    <Button x:Name="ButtonUpdate" Content="UPDATE" HorizontalAlignment="Left" Margin="120,240,0,0" VerticalAlignment="Top" Width="244" Height="70" Click="buttonUpdate_Click" FontSize="25">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Text.Length, ElementName=TextBoxOld, UpdateSourceTrigger=PropertyChanged}" Value="0">
                        <Setter Property="IsEnabled" Value="False"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Text.Length, ElementName=TextBoxNew, UpdateSourceTrigger=PropertyChanged}" Value="0">
                        <Setter Property="IsEnabled" Value="False"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>
    <Label x:Name="OldNameLabel" Content="Name" HorizontalAlignment="Left" Margin="24,70,0,0" VerticalAlignment="Top"/>
    <Label x:Name="OldIpLabel" Content="IP" HorizontalAlignment="Left" Margin="24,100,0,0" VerticalAlignment="Top"/>
    <Label x:Name="OldWebpageUriLabel" Content="WebpageUri" HorizontalAlignment="Left" Margin="24,130,0,0" VerticalAlignment="Top" />
    <TextBox x:Name="OldConnectionStringTextBox" Text="ConnectionString" HorizontalAlignment="Left" Margin="24,160,0,0" Width="120"
             VerticalAlignment="Top" Background="Linen" BorderThickness="0" IsReadOnly="True"/>
    <Label x:Name="NewNameLabel" Content="Name" HorizontalAlignment="Left" Margin="322,70,0,0" VerticalAlignment="Top"/>
    <Label x:Name="NewIpLabel" Content="IP" HorizontalAlignment="Left" Margin="322,100,0,0" VerticalAlignment="Top"/>
    <Label x:Name="NewWebpageUriLabel" Content="WebpageUri" HorizontalAlignment="Left" Margin="322,130,0,0" VerticalAlignment="Top"/>
    <TextBox x:Name="NewConnectionStringTextBox" Text="ConnectionString" HorizontalAlignment="Left" Margin="322,160,0,0" Width="120"
             VerticalAlignment="Top" Background="Linen" BorderThickness="0" IsReadOnly="True"/>
    <Label x:Name="ArrowLabel" Content="&lt;-" HorizontalAlignment="Left" Margin="221,14,0,0" VerticalAlignment="Top" FontSize="30" />
    <Label x:Name="OldVersionTextBoxLabel" Content="Old Version:" HorizontalAlignment="Left" Margin="24,4,0,0" VerticalAlignment="Top"/>
    <Label x:Name="NewVersionTextBoxLabel" Content="New Version:" HorizontalAlignment="Left" Margin="325,4,0,0" VerticalAlignment="Top"/>
    <Button x:Name="OldButtonConnectionString" Content="..." HorizontalAlignment="Left" Margin="149,158,0,0" VerticalAlignment="Top" Width="25" Click="button_ClickOldConnection">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Text.Length, ElementName=OldConnectionStringTextBox, UpdateSourceTrigger=PropertyChanged}" Value="16">
                        <Setter Property="IsEnabled" Value="False"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>
    <Button x:Name="NewButtonConnectionString" Content="..." HorizontalAlignment="Left" Margin="447,158,0,0" VerticalAlignment="Top" Width="25" Click="button_ClickNewConnection">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Text.Length, ElementName=NewConnectionStringTextBox, UpdateSourceTrigger=PropertyChanged}" Value="16">
                        <Setter Property="IsEnabled" Value="False"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>
    <Button x:Name="StartServiceButton" Content="Start Service" HorizontalAlignment="Left" Margin="10,288,0,0" VerticalAlignment="Top" Width="91" Click="buttonStartService_Click" IsEnabled="False"/>
    <TextBox x:Name="LogsTextBox" Margin="10,315,10,10" TextWrapping="Wrap" Text="Logs:" IsReadOnly="True"/>
    <CheckBox x:Name="StopServiceCheckBox" Content="Stop Service" HorizontalAlignment="Left" Margin="10,267,0,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
1

Tak. Do tego potrzebujesz później mieć ViewModel, który we właściwościach (tu już tradycyjnych, nie DP) zawiera wszystko to, co będzie potrzebne w takiej kontrolce np. dane do textboxów. Główny ViewModel okna będzie miał dwie instancje takiej klasy, bo masz dwie kontrolki. I w obu tych kontrolkach przypisujesz do ich DependencyProperty odpowiednie właściwości z odpowiedniej instancji z tych dwóch ViewModeli.

0

Dzieki wielki, po próbuje ale to chyba na tą chwile ponad moje możliwości :P

1 użytkowników online, w tym zalogowanych: 0, gości: 1