I have created a simple test project which creates a ListBox populated with Checkboxes. I have some codebehind that whenever the checkboxes are checked the TextBox above the ListBox displays the text of all the selected items. Everything works but I am now trying to create an Attached Property (again in the code behind) that allows a prefix to be included. Eventually I am looking to convert this to MVVM standards but because I am relatively new to WPF and very new to MVVM I like to work from a working sample project and gradually convert each part to an MVVM project as I find this helps me understand better what is going on. My code is below:
xaml:
<Window x:Class="CheckBoxList.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:local="clr-namespace:CheckBoxList"
mc:Ignorable="d"
Title="MainWindow" Height="400" Width="400">
<Window.Resources>
<Style x:Key="CheckBoxListStyle" TargetType="{x:Type ListBox}">
<Setter Property="SelectionMode" Value="Multiple"></Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}" >
<Setter Property="Margin" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<CheckBox
IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"
Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked">
<ContentPresenter></ContentPresenter>
</CheckBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Margin="8">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" x:Name="ListBoxTextBox"/>
<ListBox Grid.Row="1" Style="{StaticResource CheckBoxListStyle}" Name="lstProducts" local:MainWindow.PrefixMark=">"
DisplayMemberPath="ModelName">
</ListBox>
<Button Grid.Row="2" Margin="0,5,0,0" Click="cmdGetSelectedItems">Get Selected Items</Button>
<CheckBox Grid.Row="3" Content="Test" Margin="5"/>
</Grid>
xaml.cs
public static string GetPrefixMark(DependencyObject obj)
{
string t = (string)obj.GetValue(PrefixMarkProperty);
return (string)obj.GetValue(PrefixMarkProperty);
}
public static void SetPrefixMark(DependencyObject obj, string value)
{
obj.SetValue(PrefixMarkProperty, value);
string t = (string)obj.GetValue(PrefixMarkProperty);
}
// Using a DependencyProperty as the backing store for PrefixMark. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PrefixMarkProperty =
DependencyProperty.RegisterAttached("SetPrefixMark", typeof(string), typeof(MainWindow), new PropertyMetadata("('"));
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
if (sender is FrameworkElement element)
{
AddText(element);
}
}
private void AddText(FrameworkElement e)
{
StringBuilder sB = new StringBuilder("");
foreach (Product product in lstProducts.SelectedItems)
{
sB.Append(product.ModelName).Append(ValueSeparator);
}
if (sB.Length > 0)
{
sB.Remove(sB.Length - (ValueSeparator).Length, (ValueSeparator).Length);
}
if (sB.Length > 0)
{
ListBoxTextBox.Text = GetPrefixMark(e) + sB.ToString();
}
else
{
ListBoxTextBox.Text = "";
}
}
When I run the programme although the PrefixMark is set on Load when ever I check a checkbox it reverts back to the default. I can only presume this is being created twice but for the life of me I cannot figure out why and how to resolve the issue?
You should pass the actual name of the dependency property to the
Registermethod to begin with:It's not supposed to. If you want to set the
Textproperty of theTextBoxat startup, you should either bind it to a source property or set it programmatically: