0

I've a MainView with MyControl in XAML. I need to write my control using MVVM, so I've MyControl.xaml that defines the layout with some binded properties, MyControl.xaml.cs, which stores only constructor and DependencyProperties (I need to be able to set them in Styles.xaml ResourceDictioanry), MainView.xaml (with main view UI) - the C# code associated with that MainView is left unchanged.

MyControl.xaml:

<UserControl x:Class="MainWindowModule.Views.MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:prism="http://prismlibrary.com/" 
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:viewmodels="clr-namespace:MainWindowModule.ViewModels"
             d:DataContext="{d:DesignInstance Type=viewmodels:MyControlViewModel}"
             prism:ViewModelLocator.AutoWireViewModel="True">

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <prism:InvokeCommandAction Command="{Binding LoadedCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    
    <Grid>
        <Rectangle x:Name="rect" Width="{Binding Width}" />
    </Grid>
</UserControl>

MyControl.xaml.cs:

public partial class MyControl:UserControl {

        public static readonly DependencyProperty NumberProperty =
            DependencyProperty.Register("Number", typeof(int), typeof(MyControl), new PropertyMetadata(0));

        public MyControl() {
            InitializeComponent();
        }
    }

MyControlViewModel.cs:

public class MyControlViewModel:BindableBase {

        public int Number {
            get { return _number; }
            set { SetProperty(ref _number, value); }
        }

        public int Width {
            get { return _width; }
            set { SetProperty(ref _width, value);}
        }

        public DelegateCommand LoadedCommand { get; set; }

        private int _number = 0;
        private int _width = 100;

        public MyControlViewModel() {
            LoadedCommand = new DelegateCommand(OnLoad);
        }

        private void OnLoad() {
            //Load resources
        }
    }

MainView.xaml declaration of MyControl:

<Grid>
   <local:MyControl x:Name="test" />
</Grid>

My problem is that I want to be able to specify Number property value in MainView.xaml, but I cannot see this property.

Aenye_Cerbin
  • 158
  • 10

2 Answers2

1

in MyControl.xaml.cs you also need the backing properties for the dependency property

public static readonly DependencyProperty NumberProperty =
        DependencyProperty.Register("Number", typeof(int), typeof(MyControl), new PropertyMetadata(0));

public int Number
{
    get => (int)GetValue(NumberProperty );
    set => SetValue(NumberProperty , value);
}
Dean Chalk
  • 20,076
  • 6
  • 59
  • 90
  • @Aenye_Cerbin Is TristableSwitch supposed to be identical to MyControl? Otherwise use `typeof(MyControl)` as third argument of the Register method. – Clemens Mar 13 '23 at 13:18
  • @Clemens Yeah, Forgotten to change this name in this simplified example code. Will update the post. – Aenye_Cerbin Mar 13 '23 at 13:19
  • Ok, thanks syntax error vanished when cleaned solution and rebuilded it. How am I suppose to read this value (at best reacto on it's change) in MyControlViewModel? – Aenye_Cerbin Mar 13 '23 at 13:26
  • 1
    @Aenye_Cerbin You either bind to it by a RelativeSource Binding, or react on changes in a PropertyChangedCallback as shown in the answer to the duplicate question. The control should not access a private view model for this purpose. Besides that, you would simply use a TwoWay Binding like `Number="{Binding SomeViewModelProperty, Mode=TwoWay}"`. You can even declare the property so that it binds two-way by default. – Clemens Mar 13 '23 at 13:28
0

As the instance of MyControlViewModel is stored in DataContext property, its property should be able to be accessed with DataContext.[property name].

Thus, you can bind the Number property with other control in MainView.xaml like this.

<ListView SelectedIndex="{Binding ElementName=test, Path=DataContext.Number, Mode=OneWayToSource}"/>
emoacht
  • 2,764
  • 1
  • 13
  • 24