1

I am trying to implement a set of controls that will be used by various instrument wrappers/adapters in an application. The goal of these controls is to provide functionality that all of the attached devices would use such as validating an IP address rather than having each developer writing their own as new device support is added. We are also looking at moving to WPF and MVVM as part of this re-factoring. The problem I am struggling to understand is how the vm from the main window can share data (the validated IP address in this example) with the vm of the control. Does the control vm after validating the IP address write this back to the model and the main form vm gets it from there? or is there a dependency property from the control vm pushing the string into the main form VM?

The XAML for User Control This binds to the vm of the control

    <Label Content="IP Address" HorizontalAlignment="Left" VerticalAlignment="Top" Width="78"/>
    <TextBox Text="{Binding Path=Part1, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="44" RenderTransformOrigin="4.427,0.626" HorizontalContentAlignment="Center"/>
    <TextBox Text="{Binding Path=Part2, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="44" RenderTransformOrigin="4.427,0.626" HorizontalContentAlignment="Center"/>
    <TextBox Text="{Binding Path=Part3, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="44" RenderTransformOrigin="4.427,0.626" HorizontalContentAlignment="Center"/>
    <TextBox Text="{Binding Path=Part4, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="44" RenderTransformOrigin="4.427,0.626" HorizontalContentAlignment="Center"/>
    <Button Command="{Binding ValidateCommand}" Content="Validate" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" />
    <TextBox Text="{Binding Result}" TextWrapping="Wrap" Width="179" Margin="0,0,0,63.6"/>

The vm has the following properties

    public string Part1 { get; set; }
    public string Part2 { get; set; }
    public string Part3 { get; set; }
    public string Part4 { get; set; }
    private StringBuilder result = new StringBuilder();
    public string IPAddress { get; set; }

    public string Result
    {
        get { return (string)GetValue(ResultProperty); }
        set { SetValue(ResultProperty, value); }
    }

    public static readonly DependencyProperty ResultProperty =
        DependencyProperty.Register("Result", typeof(string), typeof(IPAddressViewModel), new UIPropertyMetadata(""));

and a command class for the user control button

    private readonly IPAddressViewModel _vm;
    public IPAddressValidate(IPAddressViewModel vm)
    {
        _vm = vm;
    }

    public bool CanExecute(object parameter)
    {
        // ...... 
    }

    public event EventHandler CanExecuteChanged
    {
        // ...... 
    }

    public void Execute(object parameter)
    {
        _vm.Validates();
    }

The control works as expected and enables the validate button once data has been entered then validates it on the button click. So far so good.

I then try to use this control in a form like so

    <Button Command="{Binding ConnectCommand}" Content="Connect" HorizontalAlignment="Left" Margin="10,151,0,0" VerticalAlignment="Top" Width="75" Height="22"/>
    <TextBox Text="{Binding Result}" HorizontalAlignment="Left" Height="23" Margin="124,151,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="384"/>
    <Controls:IPAddress HorizontalAlignment="Left" Margin="10,85,0,0" VerticalAlignment="Top" Height="26" Width="498"/>

I then implement the command to handle the connect button and that's where it all falls apart as I can't see a way of getting the validated string from the user control. The value is a public property of the control vm but how does the main window vm get an instance of this does it need to be injected? Is this the wrong approach or am I missing a step?

Thanks for the answer Sheridan much appreciated however the user control I have creates its vm in the constructor and not in the vm of the main window unlike the example is this incorrect?

User control code behind

public partial class IPAddress : UserControl
{
    private IPAddressViewModel _vm;

    public IPAddress()
    {
        InitializeComponent();

        //Create an insatnce of the view model and set it as the data context for this form
        _vm = new IPAddressViewModel();
        this.DataContext = _vm;
    }
}

Main Form code behind

public partial class MainWindow : Window
{
    private AdapterViewModel _vm;

    public MainWindow()
    {
        InitializeComponent();

        //Create an insatnce of the view model and set it as the data context for this form
        _vm = new AdapterViewModel();
        this.DataContext = _vm;
    }
}

I don't see how I can implement from your example

ParameterViewModel viewModel = new ParameterViewModel();
viewModel.OnParameterChange += ParameterViewModel_OnParameterChange;

Will this not create another instance of the user controls vm which isn't the one used by the view?

  • 1
    You *may* need to follow the links in my answer to the duplicate question to get further and more relevant information. The idea is simple. Define a `delegate` in the `UserControl`, attach a handler to it in `MainWindow.xaml.cs` and call it from the `UserControl` when you want to pass the data through to the `MainWindow.xaml.cs`. Please follow *all* of the provided links which explain everything *rather* than asking further questions here. – Sheridan Jul 10 '14 at 13:01

0 Answers0