I have the following scenario:
<Button Click="ClickHandler">Click Me</Button>
<TextBox x:Name="MyInputTextBox" />
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox x:Name="MyRepeatTextBox" Text="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If MyRepeatTextBox.Text == MyInputTextBox.Text I want to change the color of MyRepeatTextBox.Background to Green. If MyRepeatTextBox.Text is blank I want to change the color to red. How would I implement the button click handler?
Not sure a button event would be the best for this.
As DataTriggers are again not brought outside the WPF world, those are out. There's no IMultiValueConverter either. Behaviours are currently out, but there is a nice codeplex project for them. I would use that
public class MatchTextForegroundBehaviour : Behavior<TextBox>
{
private TextBox _attachedElement;
public static readonly DependencyProperty MatchForegroundProperty =
DependencyProperty.Register("MatchForeground", typeof(Brush),
typeof(MatchTextForegroundBehaviour),
new PropertyMetadata(new SolidColorBrush(Colors.Green), OnMatchForegroundChanged));
public static readonly DependencyProperty FallbackForegroundProperty =
DependencyProperty.Register("FallbackForeground", typeof(Brush),
typeof(MatchTextForegroundBehaviour),
new PropertyMetadata(new SolidColorBrush(Colors.Black), OnFallbackForegroundChanged));
public static readonly DependencyProperty TextToMatchProperty =
DependencyProperty.Register("TextToMatch", typeof(string),
typeof(MatchTextForegroundBehaviour),
new PropertyMetadata(null, OnTextToMatchChanged));
public Brush MatchForeground
{
get { return (Brush)GetValue(MatchForegroundProperty); }
set { SetValue(MatchForegroundProperty, value); }
}
public Brush FallbackForeground
{
get { return (Brush)GetValue(FallbackForegroundProperty); }
set { SetValue(FallbackForegroundProperty, value); }
}
public string TextToMatch
{
get { return (string)GetValue(TextToMatchProperty); }
set { SetValue(TextToMatchProperty, value); }
}
/// <summary>
/// Event when the behavior is attached to a element.
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
_attachedElement = AssociatedObject;
if(_attachedElement != null)
_attachedElement.TextChanged += (s,e) => ChangeForeground();
}
private static void OnMatchForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = (MatchTextForegroundBehaviour)d;
behavior.ChangeForeground();
}
private static void OnTextToMatchChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = (MatchTextForegroundBehaviour)d;
behavior.ChangeForeground();
}
private static void OnFallbackForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = (MatchTextForegroundBehaviour)d;
behavior.ChangeForeground();
}
private void ChangeForeground()
{
if (_attachedElement == null) return;
if (string.IsNullOrEmpty(TextToMatch)) return; // change foreground to red?
if (_attachedElement.Text == TextToMatch)
{
_attachedElement.Foreground = MatchForeground;
}
else
{
_attachedElement.Foreground = FallbackForeground;
}
}
}
And the xaml
<TextBox x:Name="MyRepeatTextBox" Text="{Binding}"
TextToMatch="{Binding Text, ElementName=MyInputTextBox}"
FallbackForeground="Black" MatchForeground="Green" />
If a button click event is really how you want to do this, you can try the following. I have not compiled this against WinRT, but I think everything used is in WinRT.
Use the following ExtensionMethod
internal static class TreeExtensions
{
public static T GetChildElement<T>(this DependencyObject element) where T :FrameworkElement
{
if (element == null) return null;
if(element.GetType() == typeof(T)) return (T)element;
T childAsT = null;
int count = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(element, i);
childAsT = child.GetChildElement<T>();
if (childAsT != null) break;
}
return childAsT;
}
}
Inside the button click event you would do the following (assuming you gave the ItemsControl a name of itemsControl:
foreach (var item in itemsControl.Items)
{
var element = itemsControl.ItemContainerGenerator.ContainerFromItem(item);
var textblock = element.GetChildElement<TextBlock>();
if (textblock != null)
{
if (textblock.Text == MyInputTextBox.Text)
textblock.Foreground = new SolidColorBrush(Colors.Green);
else
textblock.Foreground = new SolidColorBrush(Colors.Black);
}
}
Related
I'm trying to learn WinUI by building an app that can help with planning holidays. One of the things I'm trying to do is build a UI that shows a list of destinations (currently using a ListView), and then have a button to the right essentially pointing to the line between them that could pop up a UI for 'travel' between the two destinations.
This is a mockup of what I'm trying to achieve:
The buttons with the badly drawn plane and train icons should represent the travel between the two locations and therefore should be in the middle.
I've mainly been flailing about trying to get it to work using a grid inside of the DataTemplate, but haven't been able to get the 'half-way' alignment without making the gap between the destinations bigger.
Does anyone have any suggestions as to how I could achieve this, or is it a fools errand?
I guess you need to create a user control (or a custom control). Something like this:
CustomList.xaml
<UserControl
x:Class="UserControls.CustomList"
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:local="using:UserControls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="RootContainer" />
</UserControl>
CustomList.xaml
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using System.Collections.Generic;
using Windows.Foundation.Collections;
namespace UserControls;
public sealed partial class CustomList : UserControl
{
public static readonly DependencyProperty MainItemsProperty = DependencyProperty.Register(
nameof(MainItems),
typeof(IEnumerable<string>),
typeof(CustomList),
new PropertyMetadata(default, (d, e) => (d as CustomList)?.OnItemsPropertyChanged()));
public static readonly DependencyProperty SubItemsProperty = DependencyProperty.Register(
nameof(SubItems),
typeof(IEnumerable<string>),
typeof(CustomList),
new PropertyMetadata(default, (d, e) => (d as CustomList)?.OnItemsPropertyChanged()));
public CustomList()
{
this.InitializeComponent();
this.RootContainer.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0, GridUnitType.Auto) });
this.RootContainer.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0, GridUnitType.Auto) });
}
public IEnumerable<string> MainItems
{
get => (IEnumerable<string>)GetValue(MainItemsProperty);
set => SetValue(MainItemsProperty, value);
}
public IEnumerable<string> SubItems
{
get => (IEnumerable<string>)GetValue(SubItemsProperty);
set => SetValue(SubItemsProperty, value);
}
private ICollectionView? MainItemsCollectionView { get; set; }
private ICollectionView? SubItemsCollectionView { get; set; }
private void OnItemsPropertyChanged()
{
CollectionViewSource mainCollectionViewSource = new()
{
Source = MainItems
};
if (MainItemsCollectionView is not null)
{
MainItemsCollectionView.VectorChanged -= ItemsCollectionView_VectorChanged;
}
MainItemsCollectionView = mainCollectionViewSource.View;
MainItemsCollectionView.VectorChanged += ItemsCollectionView_VectorChanged;
CollectionViewSource subCollectionViewSource = new()
{
Source = SubItems
};
SubItemsCollectionView = subCollectionViewSource.View;
RefreshList();
}
private void ItemsCollectionView_VectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs #event)
{
RefreshList();
}
private void RefreshList()
{
this.RootContainer.Children.Clear();
this.RootContainer.RowDefinitions.Clear();
if (MainItemsCollectionView is not null)
{
UpdateRowDefinitions(MainItemsCollectionView.Count);
for (int i = 0; i < MainItemsCollectionView.Count; i++)
{
TextBlock mainItemTextBlock = new()
{
Text = MainItemsCollectionView[i] as string,
};
Grid.SetColumn(mainItemTextBlock, 0);
Grid.SetRow(mainItemTextBlock, i * 2);
Grid.SetRowSpan(mainItemTextBlock, 2);
this.RootContainer.Children.Add(mainItemTextBlock);
if (SubItemsCollectionView?.Count > i)
{
TextBlock subItemTextBlock = new()
{
Text = SubItemsCollectionView[i] as string,
};
Grid.SetColumn(subItemTextBlock, 1);
Grid.SetRow(subItemTextBlock, (i * 2) + 1);
Grid.SetRowSpan(subItemTextBlock, 2);
this.RootContainer.Children.Add(subItemTextBlock);
}
}
}
}
private void UpdateRowDefinitions(int mainItemsCount)
{
int requiredRowsCount = mainItemsCount * 2;
while (this.RootContainer.RowDefinitions.Count != requiredRowsCount)
{
if (this.RootContainer.RowDefinitions.Count < requiredRowsCount)
{
this.RootContainer.RowDefinitions.Add(new RowDefinition()
{
Height = new GridLength(0, GridUnitType.Auto),
});
continue;
}
if (this.RootContainer.RowDefinitions.Count > requiredRowsCount)
{
this.RootContainer.RowDefinitions.RemoveAt(this.RootContainer.RowDefinitions.Count - 1);
continue;
}
}
}
}
MainPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
namespace UserControls;
public partial class MainPageViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<string> mainItems = new()
{
"New York",
"London",
"Edinburgh"
};
[ObservableProperty]
private ObservableCollection<string> subItems = new()
{
"Airplane",
"Train",
};
}
MainPage.xaml
<Grid>
<local:CustomList
MainItems="{x:Bind ViewModel.MainItems, Mode=OneWay}"
SubItems="{x:Bind ViewModel.SubItems, Mode=OneWay}" />
</Grid>
I have a Entry control inside DataTemplate of Bindable StackLayout. I have implemented TextChanged event of Entry control with Behavior but event is not getting fired.
This is xaml code
<Frame Padding="20,14,10,10"
Grid.Column="1"
BorderColor="LightGray">
<Entry MaxLength="5"
Keyboard="Numeric"
HeightRequest="42">
<Entry.Behaviors>
<helpers:EventToCommandBehavior Command="{Binding RefreshCommand}"
EventName="TextChanged"></helpers:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>
</Frame>
Behavior classes in a single file
namespace Product.Helpers
{
public class EventToCommandBehavior : BehaviorBase<VisualElement>
{
Delegate eventHandler;
public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public string EventName
{
get { return (string)GetValue(EventNameProperty); }
set { SetValue(EventNameProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
protected override void OnAttachedTo(VisualElement bindable)
{
base.OnAttachedTo(bindable);
RegisterEvent(EventName);
}
protected override void OnDetachingFrom(VisualElement bindable)
{
DeregisterEvent(EventName);
base.OnDetachingFrom(bindable);
}
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null) return;
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
}
void RegisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name)) return;
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(AssociatedObject, eventHandler);
}
void DeregisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name) || eventHandler == null)
return;
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
eventHandler = null;
}
void OnEvent(object sender, object eventArgs)
{
if (Command == null) return;
object resolvedParameter;
resolvedParameter = eventArgs;
if (Command.CanExecute(resolvedParameter))
Command.Execute(resolvedParameter);
}
}
public class BehaviorBase<T> : Behavior<T> where T : BindableObject
{
public T AssociatedObject { get; private set; }
protected override void OnAttachedTo(T bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
if (bindable.BindingContext != null)
BindingContext = bindable.BindingContext;
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= OnBindingContextChanged;
AssociatedObject = null;
}
void OnBindingContextChanged(object sender, EventArgs e)
{
OnBindingContextChanged();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
}
}
ViewModel Code for Command
public ICommand RefreshCommand
{
get
{
return new Command(async (args) =>
{
Refresh();
});
}
}
public void Refresh()
{
var textbox = Subtotal;
}
From here I have take the code csharpcorer - behavior. How can I make it work ?
The reason you are not able to find it is because of the context.
Give your current ContentPage a name :
<ContentPage
...
x:Name="currentPage"/>
Then your Entry would look something like:
<Entry MaxLength="5"
Keyboard="Numeric"
HeightRequest="42">
<Entry.Behaviors>
<helpers:EventToCommandBehavior Command="{Binding BindingContext.RefreshCommand, Source={x:Reference currentPage}}"
EventName="TextChanged"></helpers:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>
i want to display a picker (or list) when i click in my imageButton but it didn't work, but when i create only a picker , it worked.
Xaml
<StackLayout Orientation="Horizontal" x:Name="stacklayout">
<Entry Placeholder="préciser l'entité correspondante"
ClearButtonVisibility="WhileEditing" x:Name="entit"/>
<ImageButton Source="list.png" WidthRequest="30" HeightRequest="30" x:Name="listEntité" Clicked="listEntité_Clicked"/>
Xaml.cs
private void listEntité_Clicked(object sender, EventArgs e)
{
Picker p = new Picker();
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://192.168.1.3:3000/api/adepApi/GetCurrencyLists");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await httpClient.GetAsync("http://192.168.1.3:3000/api/adepApi/GetCurrencyLists");
var content = await response.Content.ReadAsStringAsync();
ResponseDataD EL = JsonConvert.DeserializeObject<ResponseDataD>(content);
p.ItemsSource= EL.Data.DeviseList;
stacklayout.Children.Add(p.ItemsSource);
}
class DeviseModel
public class DeviseModel
{
public class DeviseL
{
// public string devis;
[JsonProperty("Label")]
public string Devis { get; set; }
[JsonProperty("Value")]
public int id { get; set; }
}
public class ResponseDataD
{
public RootModelDevise Data;
}
public class RootModelDevise : INotifyPropertyChanged
{
List<DeviseL> deviseList;
[JsonProperty("list")]
public List<DeviseL> DeviseList
{
get { return deviseList; }
set
{
if (deviseList != value)
{
deviseList = value;
OnPropertyChanged();
}
}
}
DeviseL itemDevise;
public DeviseL ItemDevise
{
get { return itemDevise; }
set
{
if (itemDevise != value)
{
itemDevise = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}}
i have an error in the line
stacklayout.Children.Add(p.ItemsSource);
under p.itemsSource :unable to convert from 'System.Collections.Ilist' to 'Xamarin.Forms.View'
i have tried to add picker by imageButton click event , but nothing appears.
Firstly, please confirm that the EL.Data.DeviseList have list value, you have list binding to Picker, then adding picker to current contentPage.
public partial class Page16 : ContentPage
{
private List<string> list;
public Page16()
{
InitializeComponent();
list = new List<string>();
list.Add("test 1");
list.Add("test 2");
list.Add("test 3");
list.Add("test 4");
}
private void imagebutton1_Clicked(object sender, EventArgs e)
{
Picker p = new Picker();
p.ItemsSource = list;
stacklayout.Children.Add(p);
}
}
<StackLayout x:Name="stacklayout">
<ImageButton
x:Name="imagebutton1"
Clicked="imagebutton1_Clicked"
HeightRequest="30"
Source="plu3.png"
WidthRequest="30" />
</StackLayout>
Update:
private void imagebutton1_Clicked(object sender, EventArgs e)
{
Picker p = new Picker();
p.SelectedIndexChanged += P_SelectedIndexChanged;
p.ItemsSource = devs;
p.ItemDisplayBinding = new Binding("Devis");
stacklayout.Children.Add(p);
}
private void P_SelectedIndexChanged(object sender, EventArgs e)
{
Picker p = sender as Picker;
DeviseL selectitem = p.SelectedItem as DeviseL;
entit.Text =selectitem.Devis;
}
im working with custon entry rendered, i need to hear from xaml in my custom render when i clicked my button
i have this code in my xaml
<local:MyEntry eventRefresh="true">
when i clicked my button this function is actived
private async void Execute(object sender)
{
var entry = ((MyEntry)view);
entry.eventRefresh = "false";
but my EntryRendered donot hear the change
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var element = Element as MyEntry;
You should define the property eventRefresh as Bindable Property .
in your custom Entry
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms;
namespace xxx
{
public class MyEntry:Entry,INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public static readonly BindableProperty eventRefreshProperty = BindableProperty.Create("eventRefresh", typeof(bool), typeof(MyEntry), true,propertyChanged:(obj,oldValue,newValue)=> {
//var entry = obj as MyEntry;
// entry.Text = newValue.ToString();
});
bool refresh;
public bool eventRefresh
{
get { return refresh; }
set {
if(refresh !=value)
{
refresh = value;
NotifyPropertyChanged("eventRefresh");
}
}
}
public MyEntry()
{
}
}
}
in xaml
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<local:MyEntry eventRefresh="{Binding Refresh}" BackgroundColor="{Binding BGcolor}" WidthRequest="200" HeightRequest="50" />
<Button Command="{Binding ClickCommand}" />
</StackLayout>
in View Model
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Color color;
public Color BGcolor
{
get { return color; }
set
{
if (color != value)
{
color = value;
NotifyPropertyChanged("BGcolor");
}
}
}
bool refresh;
public bool Refresh
{
get { return refresh; }
set
{
if (refresh != value)
{
refresh = value;
NotifyPropertyChanged("Refresh");
}
}
}
public ICommand ClickCommand { get; set; }
public MyViewModel()
{
BGcolor = Color.LightPink;
ClickCommand = new Command(()=> {
BGcolor = Color.Red;
});
}
}
in Custom Renderer
using System.ComponentModel;
using Android.Content;
using xxx;
using xxx.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly:ExportRenderer(typeof(MyEntry),typeof(NyEntryRenderer))]
namespace xxx.Droid
{
public class NyEntryRenderer : EntryRenderer
{
public NyEntryRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Element.TextChanged += Element_TextChanged;
}
}
private void Element_TextChanged(object sender, TextChangedEventArgs e)
{
// var content = Element.Text;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == MyEntry.BackgroundColorProperty.PropertyName)
{
// will been invoked when click button
}
}
}
}
Make your view model like this.
public class YourViewModel
{
public Command command
{
get
{
return new Command(() => {
//Change here button background colors
BackgroundColor = Color.Green;
});
}
}
private _backgroundColor = Color.White;
public Color BackgroundColor
{
get { return _backgroundColor;}
set
{
if (value == _backgroundColor)
return;
_backgroundColor = value;
NotifyOnPropertyChanged(nameof(BackgroundColor));
}
}
}
Your XAML
<local:MyEntry Text="{Binding Password}" Placeholder="Enter" />
<Button Text="send" Command="{Binding command}" BackgroundColor="{Binding BackgroundColor}"></Button>
what is the easiest way to bind selected state of listview's item to model's boolean property?
I have model:
class Model {
public string Name { get; set; }
public bool Selected { get; set; }
}
And listview:
<ListView x:Name="myListView" SelectionMode="Multiple">
<ListView.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
I bind items to the listview:
myListView.ItemsSource = // list of Model instances
I want the Selected property of Model to always reflect whether it is selected or not in myListView. So - by selecting/deselecting the item in myListView, it will hold the apropriate bool value or by setting Selected property myListView will select/deselect appropriate item.
what is the easiest way to bind selected state of listview's item to model's boolean property?
I'm not sure if this is the most easiest way, but for me I think it is the easiest way to bind SelectorItem.IsSelected property of ListViewItem to your Selected property in model. Only the problem is, we all know each item of ListView is an instance of ListViewItem, but when we use DataTemplate to build the item structure for ListViewItem, ListViewItems are not available in design-time. So my idea is to bind this property in code behind, just for example here:
<ListView x:Name="myListView" SelectionMode="Multiple" Loaded="myListView_Loaded" ItemsSource="{x:Bind Collection}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
code behind:
private ObservableCollection<Model> Collection = new ObservableCollection<Model>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
for (int i = 0; i < 100; i++)
{
Collection.Add(new Model { Name = "Name " + i });
}
}
private void myListView_Loaded(object sender, RoutedEventArgs e)
{
IEnumerable<ListViewItem> lvItems = FindVisualChildren<ListViewItem>(myListView);
if (lvItems != null)
{
foreach (ListViewItem lvitem in lvItems)
{
Model model = lvitem.Content as Model;
Binding b = new Binding
{
Source = model,
Path = new PropertyPath("Selected"),
Mode = BindingMode.TwoWay,
};
BindingOperations.SetBinding(lvitem, ListViewItem.IsSelectedProperty, b);
}
}
}
private static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
public class Model : INotifyPropertyChanged
{
public string Name { get; set; }
private bool _Selected;
public bool Selected
{
get { return _Selected; }
set
{
if (value != _Selected)
{
_Selected = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I think the perfect way would be to implement the ListView.ItemSelectionChanged event, and iterate through each item in the list view model to set it to true for the item which is selected, false for the rest items.
However, You may want to try something like this, although honestly I'm not sure if this is the correct way:
class Model {
public string Name { get; set; }
public bool Selected
{
get
{
return MyListView.SelectedItems.Count(x => x.Name == Name) > 0;
}
}
}