I have a list of strings defined as a dependency property. I am assigning the values of the list's items via xaml. I can assign literal string values, but I do not know how to bind those values to data from viewmodel.
public static readonly DependencyProperty StringArgsProperty = DependencyProperty.Register(
"StringArgs", typeof(List<string>), typeof(GameTextBlock), new FrameworkPropertyMetadata(new List<string>()));
public List<string> StringArgs
{
get { return (List<string>)GetValue(StringArgsProperty); }
set { SetValue(StringArgsProperty, value); }
}
Here's how I can bind items to said list currently:
<common:GameTextBlock.StringArgs>
<sys:String>arg1</sys:String>
<sys:String>arg2</sys:String>
</common:GameTextBlock.StringArgs>
What I am trying to do is replace arg1/arg2 with values from ViewModel. If I wasn't assigning to the list's items I could do "{Binding NameOfField}".
I do not want to create the whole list in ViewModel and bind the list, because I want to be able to pick and choose the items using only xaml. Can this be achieved?
EDIT: A more clear example of what I want to achieve:
public class ViewModel
{
public string Item1 {get; set;}
public string Item2 {get; set;}
public string Item3 {get; set;}
}
And then I want to be able to use them in one xaml containing multiple GameTextBlocks like this:
<GameTextBlock x:Name = "txt1" >
<GameTextBlock.StringArgs>
<sys:String>{Binding VMItem1}</sys:String>
<sys:String>{Binding VMItem3}</sys:String>
</GameTextBlock.StringArgs>
</GameTextBlock>
<GameTextBlock x:Name = "txt2" >
<GameTextBlock.StringArgs>
<sys:String>{Binding VMItem1}</sys:String>
<sys:String>{Binding VMItem2}</sys:String>
</GameTextBlock.StringArgs>
</GameTextBlock>
<GameTextBlock x:Name = "txt3" >
<GameTextBlock.StringArgs>
<sys:String>{Binding VMItem1}</sys:String>
</GameTextBlock.StringArgs>
</GameTextBlock>
Static data on a xaml page cannot change. Move the list structures to the code behind and on the change handler of the dependency property move the data as needed to the property lists. Regardless, this is how it should be done.
If you need two way transfer, then you will need more code behind to move the data from the control lists on the page back to the storage; still, this can be used as a template.
Here are the lists on the custom control to be split out to:
public partial class ShowDependency : UserControl, INotifyPropertyChanged
{
private List<string> _Text1;
public List<string> Text1
{
get { return _Text1; }
set { _Text1 = value; OnPropertyChanged(nameof(Text1)); }
}
private List<string> _Text2;
public List<string> Text2
{
get { return _Text2; }
set { _Text2 = value; OnPropertyChanged(nameof(Text2)); }
}
Here is the dependency property which will hold the incoming list from the VM
#region public List<string> Storage
/// <summary>Storage is a transfer from the Main VM</summary>
public List<string> Storage
{
get => (List<string>)GetValue(StorageProperty);
set => SetValue(StorageProperty, value);
}
/// <summary>Identifies the Storage dependency property.</summary>
public static readonly DependencyProperty StorageProperty =
DependencyProperty.Register(
"Storage",
typeof(List<string>),
typeof(ShowDependency),
new PropertyMetadata(null, OnStoragePropertyChanged));
Once bound, it smurfs the data into the lists.
/// <summary>StorageProperty property changed handler.</summary>
/// <param name="d">ShowDependency that changed its Storage.</param>
/// <param name="e">Event arguments.</param>
private static void OnStoragePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ShowDependency source)
{
var value = (List<string>)e.NewValue;
if (value != null)
{
var l1 = new List<string>();
var l2 = new List<string>();
int count = 1;
foreach (var item in value)
if ((count++ % 2) == 0)
l1.Add(item);
else
l2.Add(item);
source.Text1 = l1;
source.Text2 = l2;
}
}
}
#endregion public List<string> Storage
new List<string>() { "Alpha", "Baker", "Tango", "Omega" }
<UserControl x:Class="ExamplesInWPF.Controls.ShowDependency"
...
d:DesignHeight="450" d:DesignWidth="800"
x:Name="MyUserControl">
<StackPanel Orientation="Vertical">
<ListBox Margin="6" ItemsSource="{Binding Text1, ElementName=MyUserControl}"/>
<ListBox Margin="6" ItemsSource="{Binding Text2, ElementName=MyUserControl}"/>
</StackPanel>
</UserControl>
As an aside I have always used these Control dependency property snippets
Disregard the Silverlight part, they are still good and work up to.Net 6 Xaml/WPF.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.