WPF user data management not working

I am creating a simple User Control combining a popup with a text view, nothing crazy. When I first set it up in a window to completely style it, it worked fine, but when I moved it to User Control to finish it, it wonโ€™t work correctly.

I pass the value of min and max to the control, and then automatically creates a list of numbers to select from this range. In the user element, the list of numbers is not anchored correctly, who knows why. Maybe someone can take a look at my code.

I read a bunch of other questions about this, but I don't know what is going on. I am not getting any errors in my output window, so there are no hints. Anyway, here is the code -

UserControl.xaml

<UserControl x:Class="UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Me" DataContext="{Binding RelativeSource={RelativeSource Self}}"> <StackPanel> <TextBox Name="myTextbox" Height="30" Margin="0" FontSize="14" IsReadOnly="True" Padding="5,2" Text="{Binding Value}" /> <Popup x:Name="myPopup" PlacementTarget="{Binding ElementName=myTextbox}" StaysOpen="True"> <Popup.Style> <Style TargetType="{x:Type Popup}"> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=myTextbox, Path=IsFocused}" Value="True"> <Setter Property="IsOpen" Value="True" /> </DataTrigger> </Style.Triggers> </Style> </Popup.Style> <StackPanel> <ListView Name="myListView" Height="100" MaxHeight="300" ItemsSource="{Binding List, UpdateSourceTrigger=PropertyChanged}" SelectionChanged="ListView_SelectionChanged"> <ListView.ItemTemplate> <DataTemplate> <Label Width="100" Height="30" Margin="0" Content="{Binding}" FontFamily="Segoe UI" FontSize="14" Padding="5,2" /> </DataTemplate> </ListView.ItemTemplate> </ListView> <Button Width="200" Height="30" /> </StackPanel> </Popup> </StackPanel> 

UserControl.xaml.vb

 Imports System.ComponentModel Imports System.Linq.Expressions Imports System.Collections.ObjectModel Class UserControl1 ' Dependency Properties Public Shared ReadOnly ListProperty As DependencyProperty = DependencyProperty.Register("List", GetType(ObservableCollection(Of Integer)), GetType(MainWindow)) Public Shared ReadOnly ValueProperty As DependencyProperty = DependencyProperty.Register("Value", GetType(Integer), GetType(MainWindow)) Public Shared ReadOnly MaxValueProperty As DependencyProperty = DependencyProperty.Register("MaxValue", GetType(Integer), GetType(MainWindow)) Public Shared ReadOnly MinValueProperty As DependencyProperty = DependencyProperty.Register("MinValue", GetType(Integer), GetType(MainWindow)) ' Properties Public Property List As ObservableCollection(Of Integer) Get Return DirectCast(GetValue(ListProperty), ObservableCollection(Of Integer)) End Get Set(value As ObservableCollection(Of Integer)) SetValue(ListProperty, value) End Set End Property Public Property Value As Integer Get Return DirectCast(GetValue(ValueProperty), Integer) End Get Set(value As Integer) SetValue(ValueProperty, value) End Set End Property Public Property MaxValue As Integer Get Return DirectCast(GetValue(MaxValueProperty), Integer) End Get Set(value As Integer) SetValue(MaxValueProperty, value) End Set End Property Public Property MinValue As Integer Get Return DirectCast(GetValue(MinValueProperty), Integer) End Get Set(value As Integer) SetValue(MinValueProperty, value) End Set End Property Private Sub ListView_SelectionChanged(sender As System.Object, e As System.Windows.Controls.SelectionChangedEventArgs) Value = List(myListView.SelectedIndex) End Sub Private Sub UserControl1_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded List = New ObservableCollection(Of Integer) ' Add all available numbers into the list For iCounter As Integer = MinValue To MaxValue List.Add(iCounter) Next ' Set the selected index on the list for the value myListView.SelectedIndex = Value - MinValue End Sub End Class 

Just for reference, when I checked this, I set the Min and Max values โ€‹โ€‹both in the window settings and in the usercontrol setting.

+2
source share
3 answers

I think you made the same mistake that I was used to when I first started learning WPF. I can not guarantee that this is the cause of your problem, but since this is the only one that I see, I will address it. Unfortunately, there are so many bad tutorials and quick examples that show the connection of UserControl.DataContext to itself:

 DataContext="{Binding RelativeSource={RelativeSource Self}}" 

Or:

 DataContext = this; 

Now this is perfectly acceptable if you do not want Bind on the UserControl from the outside, because it is a quick and easy way to connect with the properties defined in the code behind. However, when you want Bind use properties from outside the control, you will find problems. In these cases (if not in all cases), you should use RelativeSource Binding to Bind for your code for the properties:

 <TextBox Name="myTextbox" Height="30" Margin="0" FontSize="14" IsReadOnly="True" Padding="5,2" Text="{Binding Value, RelativeSource={RelativeSource AncestorType={ x:Type UserControl1}}}" /> 

In this Binding , UserControl1 is the name of the UserControl that declared the property. This should be done in all internal Binding s. Thus, the DataContext not set to UserControl , but Binding still finds the properties.

You can learn more about RelativeSource on the RelativeSource MarkupExtension page on MSDN.

+10
source

Since I canโ€™t comment on Sheridan, I have to give a new answer, sorry for that.

As long as I love this decision

 DataContext="{Binding RelativeSource={RelativeSource Self}}" 

he fails (as Sheridan noted) quickly.

What you can do is simply set the DataContext of the contents of your User Control

 <UserControl x:Class="Example.View.Controls.MyUserControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:controls="clr-namespace:Example.View.Controls" mc:Ignorable="d"> <Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls:MyUserControl}}}"> </Grid> 

Thus, all of the following Bindings have less Boilerplate code, since you can simply bind directly to your DP from code, for example:

 <Label Content="{Binding MyLabel}"/> 
+7
source

As for Windows Apps (Windows 8 and Windows 10 UWP) , you must specify your control and specify it in your XAML file using Path and ElementName

 <UserControl x:Class="MyControl" 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" x:Name="Control" mc:Ignorable="d" > <Grid Height="240" VerticalAlignment="Top"> <Rectangle Fill="{Binding ElementName=Control, Path=Background}" /> </Grid> </UserControl> 

``

0
source

All Articles