I am creating a multiselect combobox in Windows 8 as shown in below image:
For this I have created custom control code for which is mentioned below:
The problem with below code is that
on selecting all the all items are not selected
Selected items are not displayed in textbox
How can I fix that?
XAML:
<UserControl
x:Class="App5.MultiSelectComboBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App5"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
x:Name="thisUC"
d:DesignWidth="400">
<ComboBox
x:Name="MultiSelectCombo"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Width="400" Height="20"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Title}" Foreground="Black"
IsChecked="{Binding ElementName=thisUC, Path=IsSelected, Mode=TwoWay}"
Click="CheckBox_Click" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ControlTemplate TargetType="ComboBox">
<Grid >
<ToggleButton
x:Name="ToggleButton"
Grid.Column="2" IsChecked="{TemplateBinding IsDropDownOpen}"
ClickMode="Press" HorizontalContentAlignment="Left" >
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="18"/>
</Grid.ColumnDefinitions>
<Border
x:Name="Border"
Grid.ColumnSpan="2"
CornerRadius="2"
Background="White"
BorderBrush="Black"
BorderThickness="1,1,1,1" />
<Border
x:Name="BorderComp"
Grid.Column="0"
CornerRadius="2"
Margin="1"
Background="White"
BorderBrush="Black"
BorderThickness="0,0,0,0" >
<TextBlock Foreground="Black" Text="{TemplateBinding TextValue}"
Padding="3" />
</Border>
<Path
x:Name="Arrow"
Grid.Column="1"
Fill="Black"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<Popup
Name="Popup"
IsOpen="{TemplateBinding IsDropDownOpen}"
>
<Grid
Name="DropDown"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder"
BorderThickness="1" Background="White"
BorderBrush="Black"/>
<ScrollViewer Margin="4,6,4,6" DataContext="{Binding}">
<StackPanel />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<!--<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
</ControlTemplate.Triggers>-->
</ControlTemplate>
</ComboBox>
</UserControl>
C#
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
namespace App5
{
public sealed partial class MultiSelectComboBox : UserControl
{
private ObservableCollection<Node> _nodeList;
public MultiSelectComboBox()
{
InitializeComponent();
_nodeList = new ObservableCollection<Node>();
}
#region Dependency Properties
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(Dictionary<string, object>), typeof(MultiSelectComboBox), new PropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnItemsSourceChanged)));
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(Dictionary<string, object>), typeof(MultiSelectComboBox), new PropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnSelectedItemsChanged)));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("TextValue", typeof(string), typeof(MultiSelectComboBox), new PropertyMetadata(null));
public static readonly DependencyProperty DefaultTextProperty =
DependencyProperty.Register("DefaultText", typeof(string), typeof(MultiSelectComboBox), new PropertyMetadata(null));
public Dictionary<string, object> ItemsSource
{
get { return (Dictionary<string, object>)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
}
}
public Dictionary<string, object> SelectedItems
{
get { return (Dictionary<string, object>)GetValue(SelectedItemsProperty); }
set
{
SetValue(SelectedItemsProperty, value);
}
}
public string TextValue
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public string DefaultText
{
get { return (string)GetValue(DefaultTextProperty); }
set { SetValue(DefaultTextProperty, value); }
}
#endregion
#region Events
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.DisplayInControl();
}
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.SelectNodes();
control.SetText();
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox clickedBox = (CheckBox)sender;
if (clickedBox.Content == "All")
{
if (clickedBox.IsChecked.Value)
{
foreach (Node node in _nodeList)
{
node.IsSelected = true;
}
}
else
{
foreach (Node node in _nodeList)
{
node.IsSelected = false;
}
}
}
else
{
int _selectedCount = 0;
foreach (Node s in _nodeList)
{
if (s.IsSelected && s.Title != "All")
_selectedCount++;
}
if (_selectedCount == _nodeList.Count - 1)
_nodeList.FirstOrDefault(i => i.Title == "All").IsSelected = true;
else
_nodeList.FirstOrDefault(i => i.Title == "All").IsSelected = false;
}
SetSelectedItems();
SetText();
}
#endregion
#region Methods
private void SelectNodes()
{
foreach (KeyValuePair<string, object> keyValue in SelectedItems)
{
Node node = _nodeList.FirstOrDefault(i => i.Title == keyValue.Key);
if (node != null)
node.IsSelected = true;
}
}
private void SetSelectedItems()
{
if (SelectedItems == null)
SelectedItems = new Dictionary<string, object>();
SelectedItems.Clear();
foreach (Node node in _nodeList)
{
if (node.IsSelected && node.Title != "All")
{
if (this.ItemsSource.Count > 0)
SelectedItems.Add(node.Title, this.ItemsSource[node.Title]);
}
}
}
private void DisplayInControl()
{
_nodeList.Clear();
if (this.ItemsSource.Count > 0)
_nodeList.Add(new Node("All"));
foreach (KeyValuePair<string, object> keyValue in this.ItemsSource)
{
Node node = new Node(keyValue.Key);
_nodeList.Add(node);
}
MultiSelectCombo.ItemsSource = _nodeList;
}
private void SetText()
{
if (this.SelectedItems != null)
{
StringBuilder displayText = new StringBuilder();
foreach (Node s in _nodeList)
{
if (s.IsSelected == true && s.Title == "All")
{
displayText = new StringBuilder();
displayText.Append("All");
break;
}
else if (s.IsSelected == true && s.Title != "All")
{
displayText.Append(s.Title);
displayText.Append(',');
}
}
this.TextValue = displayText.ToString().TrimEnd(new char[] { ',' });
}
// set DefaultText if nothing else selected
if (string.IsNullOrEmpty(this.TextValue))
{
this.TextValue = this.DefaultText;
}
}
#endregion
}
public class Node : INotifyPropertyChanged
{
private string _title;
private bool _isSelected;
#region ctor
public Node(string title)
{
Title = title;
}
#endregion
#region Properties
public string Title
{
get
{
return _title;
}
set
{
_title = value;
NotifyPropertyChanged("Title");
}
}
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
I think I understand what you want. Overall, I would recommend a slightly different approach. I would recommend, for one, that you not use a ComboBox to accomplish this - an ItemsControl will accomplish what you want with less work and overhead. Using a Popup like you are is great, but let me show you a slightly simplified way that (this is the best part) works the way you are asking in your question.
Here's your XAML:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.DataContext>
<local:ViewModel/>
</Grid.DataContext>
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox Width="200" FontSize="24" Text="{Binding Header, Mode=TwoWay}"
IsReadOnly="True" TextWrapping="Wrap" MaxHeight="200" />
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="200" Width="200" Background="White">
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Text}"
FontSize="24"
Foreground="Black"
IsChecked="{Binding IsChecked, Mode=TwoWay}"
IsThreeState="False" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</StackPanel>
</Grid>
Here's your code-behind:
public class Item : BindableBase
{
public string Text { get; set; }
bool _IsChecked = default(bool);
public bool IsChecked { get { return _IsChecked; } set { SetProperty(ref _IsChecked, value); } }
}
public class ViewModel : BindableBase
{
public ViewModel()
{
_Items = new ObservableCollection<Item>(Enumerable.Range(1, 10)
.Select(x => new Item()
{
Text = string.Format("Item {0}", x),
IsChecked = (x < 4) ? true : false,
}));
foreach (var item in this.Items)
item.PropertyChanged += (s, e) => base.RaisePropertyChanged("Header");
}
public string Header
{
get
{
var array = this.Items
.Where(x => x.IsChecked)
.Select(x => x.Text).ToArray();
if (!array.Any())
return "None";
return string.Join("; ", array);
}
}
ObservableCollection<Item> _Items;
public ObservableCollection<Item> Items { get { return _Items; } }
}
public abstract class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void SetProperty<T>(ref T storage, T value,
[System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
if (!object.Equals(storage, value))
{
storage = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
protected void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Best of luck!
Your all code is correct, except one thing, that's data binding of CheckBox in ComboBox's DataTemplate. You don't need to use ElementName=thisUC
Incorrect
<CheckBox Content="{Binding Title}" Foreground="Black"
IsChecked="{Binding ElementName=thisUC, Path=IsSelected, Mode=TwoWay}"
Click="CheckBox_Click" />
Correct
<CheckBox Content="{Binding Title}" Foreground="Black" Click="CheckBox_Click"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"/>
Related
Ihave this scenario: A ListView and every Cell is a frame. When showing the list all frames backgroudcolor is white when i click on frame i want the color to change in blie. I change the color but not refreshing. This is my code:
In xaml page
<pages:PopupPage.Resources>
<local1:ChangeFrameBackgroudColor x:Key="ChangeFrameBackgroudColor" />
</ResourceDictionary>-->
</pages:PopupPage.Resources>
<ListView x:Name="IzberiFirmaListView" HasUnevenRows="True" ItemsSource="{Binding KorisnikFirmi}" SelectedItem="{Binding IzbranaFirmaId } " Header="{Binding}" ItemTapped="IzberiFirmaListView_ItemTapped">
<ListView.ItemTemplate >
<DataTemplate>
<local:ExtendedViewCell SelectedBackgroundColor="#2188ff" >
<StackLayout Padding="20, 10" >
<Frame x:Name="frameLabel" BorderColor="#2188ff" BackgroundColor="{Binding IsActive, Converter={StaticResource ChangeFrameBackgroudColor}}">
<Label FontAttributes="Bold" FontSize="18" TextColor="Black" Text="{Binding Naziv}" ></Label>
</Frame>
</StackLayout>
</local:ExtendedViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.HeaderTemplate>
<DataTemplate>
<ContentView BackgroundColor="#006BE6" >
<Label Margin="10" HorizontalOptions="CenterAndExpand" Text="ОДБЕРЕТЕ ФИРМА" TextColor="White" FontSize="20" FontAttributes="Bold"/>
</ContentView>
</DataTemplate>
</ListView.HeaderTemplate>
</ListView>
In xaml.cs Page:
private void IzberiFirmaListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
var vm = BindingContext as OdberiFirmaPopupViewModel;
var firm = e.Item as SysDashFirma;
vm.ChangeColorOnItemSelected(firm);
}
In viewModel
public List<SysDashFirma> KorisnikFirmi
{
get { return korisnikFirmi; }
set
{
if (korisnikFirmi != value)
{
korisnikFirmi = value;
SetProperty(ref korisnikFirmi, value);
OnPropertyChanged("KorisnikFirmi");
}
}
}
public void ChangeColorOnItemSelected(SysDashFirma firm)
{
if (_oldFirmSelected == firm)
{
//firm.BackColor = "#2188ff";
firm.IsActive = true;
UpdateSelectedFirmItemColor(firm);
}
else
{
if(_oldFirmSelected != null)
{
//_oldFirmSelected.BackColor = "#f5f5f5";
_oldFirmSelected.IsActive = false;
UpdateSelectedFirmItemColor(_oldFirmSelected);
}
// firm.BackColor = "#2188ff";
firm.IsActive = true;
UpdateSelectedFirmItemColor(firm);
}
_oldFirmSelected = firm;
}
private void UpdateSelectedFirmItemColor(SysDashFirma firm)
{
var index = KorisnikFirmi.IndexOf(firm);
KorisnikFirmi.Remove(firm);
KorisnikFirmi.Insert(index,firm);
}
Changes are made in the list ,flag is changed, probably cant refresh the bidning context to converter read all from start.
Use OnPropertyChanged for the IsActive property to notify the UI about its change.
public class Firm : INotifyPropertyChanged
{
private string name = "Unknown";
public string Name
{
get
{
return name;
}
set
{
name = value;
OnPropertyChanged();
}
}
private bool isActive;
public bool IsActive
{
get
{
return isActive;
}
set
{
isActive = value;
OnPropertyChanged();
}
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
I would suggest changing the IsActive property alone as removing and adding the item is not necessary.
<ListView
ItemTapped="ListView_ItemTapped"
ItemsSource="{Binding FirmCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame
Padding="2"
BackgroundColor="{Binding IsActive, Converter={StaticResource converterTest}}">
<Label Text="{Binding Name}"/>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ViewModel
public class ViewModel : INotifyPropertyChanged
{
....
....
private Firm oldSelectedFirm;
public Firm OldSelectedFirm
{
get
{
return oldSelectedFirm;
}
set
{
oldSelectedFirm = value;
OnPropertyChanged();
}
}
...
...
}
Xaml.cs
void ListView_ItemTapped(System.Object sender, Xamarin.Forms.ItemTappedEventArgs e)
{
var tappedFirm = (e.Item as Firm);
var vm = (BindingContext as ViewModel);
if (vm.OldSelectedFirm != null)
vm.OldSelectedFirm.IsActive = false;
tappedFirm.IsActive = true;
vm.OldSelectedFirm = tappedFirm;
}
I have 2 ObservableCollection<T>s and each of the them has their Cards.
public class Card: INotifyPropertyChanged
{
private string _CardTitle;
public string CardTitle
{
get { return _CardTitle; }
set
{
_CardTitle = value;
OnPropertyChanged("CardTitle");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
Now when a CardTitle of the card is changed it is reflected on the UI thanks to PropertyChangedEventHandler.
But when I move a card from one collection to another and then change the CardTitle, I get handler as null thus, PropertyChangedEventHandler is not fired and I cannot see the change in UI.
I have scratched my head enough but cannot figure out why. If anyone has any idea then please help me before I get in trouble.
What do you mean by "move"? You remove from first collection, and add to second yes? Does your datacontext implement INotifyPropertyChanged?
I tried to reproduce your code, but i didn't have any problem. Look, maybe you find some hints:
MainPage.xaml.cs
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
this.DataContext = this;
}
private ObservableCollection<Card> _first;
public ObservableCollection<Card> First
{
get { return _first; }
set
{
_first = value;
OnPropertyChanged("First");
}
}
private ObservableCollection<Card> _second;
public ObservableCollection<Card> Second
{
get { return _second; }
set
{
_second = value;
OnPropertyChanged("Second");
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
//Init collections
}
private void ChangeItemName(object sender, RoutedEventArgs e)
{
var card = (sender as Button).DataContext as Card;
card.CardTitle = ":)";
}
private void ChangeCollection(object sender, RoutedEventArgs e)
{
var card = (sender as Button).DataContext as Card;
First.Remove(card);
Second.Add(card);
card.CardTitle = "xD";
}
MainPage.xaml
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding First}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding CardTitle}" />
<Button Content="Change name" Click="ChangeItemName" />
<Button Content="Change collection" Click="ChangeCollection" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView ItemsSource="{Binding Second}" Grid.Column="1">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding CardTitle}" />
<Button Content="Change name" Click="ChangeItemName" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</StackPanel>
I need to track the Current Column Name and Sort Direction In WPF MVVM DataGrid. I know how to do it in code behind. Plase see the code as follows:
private void columnHeader_Click(object sender, RoutedEventArgs e)
{
var columnHeader = sender as DataGridColumnHeader;
if (columnHeader != null)
{
columnName = ((DataGridColumnHeader)sender).Content.ToString();
ListSortDirection sortDirection = (((DataGridColumnHeader)sender).SortDirection != ListSortDirection.Ascending) ?
ListSortDirection.Ascending : ListSortDirection.Descending;
txb1.Text = columnName;
txb2.Text = sortDirection.ToString();
}
}
However, I am blocked in MVVM. In the View Model, I wrote codes in method sort() in SortCommand, but they did not work. I would appreciate if any one can help. Below are three files.
1) Xaml
<Window x:Class="SortSampleMVVM1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:se="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="Test"
ItemsSource="{Binding}"
AutoGenerateColumns="False" >
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Command"
Value="{Binding SortCommand}"/>
<Setter Property="CommandParameter"
Value="{Binding Path=Content, RelativeSource={RelativeSource Self}}"/>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid Name="dataGrid1" AutoGenerateColumns="False" ItemsSource="{Binding ViewSource.View}" >
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID }"
SortDirection="Descending" />
<DataGridTextColumn Header="firstName" Binding="{Binding firstName}"/>
<DataGridTextColumn Header="lastName" Binding="{Binding lastName}"/>
</DataGrid.Columns>
</DataGrid>
<Label Content="Column Name" HorizontalAlignment="Left" Margin="100,166,0,0" VerticalAlignment="Top"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="250,169,0,0" TextWrapping="Wrap" Name="txb1" Text="{Binding ColumnName}" VerticalAlignment="Top" Width="150" />
<Label Content="Sorting direction" HorizontalAlignment="Left" Margin="100,229,0,0" VerticalAlignment="Top"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="250,232,0,0" TextWrapping="Wrap" Name="txb2" Text="{Binding SortDirection}" VerticalAlignment="Top" Width="150" />
<Button Content="Refresh" Name="btnRefresh1" HorizontalAlignment="Left" Margin="140,273,0,0" VerticalAlignment="Top" Width="75" Command="{Binding Refresh1Command}" />
<Button Content="Refresh Keep Sort" Name="btnRefresh2" HorizontalAlignment="Left" Margin="282,273,0,0" VerticalAlignment="Top" Width="125" Command="{Binding Refresh2Command}" />
</Grid>
</Window>
2) Code behind
using System.Windows;**strong text**
using System.Collections.ObjectModel;
using System.Collections.Generic;
namespace SortSampleMVVM1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new SortViewModel();
}
}
}
3) View Model
using System;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows.Controls.Primitives;
using System.Windows;
using System.Windows.Data;
using System.Collections.ObjectModel;
namespace SortSampleMVVM1
{
class SortViewModel: INotifyPropertyChanged
{
public CollectionViewSource ViewSource { get; set; }
public ObservableCollection<MyData> Collection {get; set;}
private string _columnName;
private ListSortDirection _sortDirection;
private ICommand _sortCommand;
private ICommand _refresh1Command;
private ICommand _refresh2Command;
public SortViewModel ()
{
this.Collection = new ObservableCollection<MyData>();
Collection.Add(new MyData(1, "David", "Lee"));
Collection.Add(new MyData(2, "John", "kim"));
Collection.Add(new MyData(3, "Michael", "Wadsworth"));
Collection.Add(new MyData(4, "Chris", "Smith"));
Collection.Add(new MyData(5, "Peter", "Chen"));
Collection.Add(new MyData(6, "Jonas", "Zhang"));
this.ViewSource = new CollectionViewSource();
ViewSource.Source = this.Collection;
}
public event PropertyChangedEventHandler PropertyChanged;
public string ColumnName
{
get { return _columnName; }
set
{
_columnName = value;
OnPropertyChanged("ColumnName");
}
}
public ListSortDirection SortDirection
{
get { return _sortDirection; }
set
{
_sortDirection = value;
OnPropertyChanged("SortDirection");
}
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
#region SortCommand
public ICommand SortCommand
{
get
{
if (_sortCommand == null)
{
_sortCommand = new RelayCommand(param => this.sort(),
null);
}
return _sortCommand;
}
}
private void sort()
{
//var columnHeader = (object)sender as DataGridColumnHeader;
//if (columnHeader != null)
//{
// _columnName = ViewSource.GetValuecolumnName ((DataGridColumnHeader)sender).Content.ToString();
// ListSortDirection sortDirection = (((DataGridColumnHeader)sender).SortDirection != ListSortDirection.Ascending) ?
// ListSortDirection.Ascending : ListSortDirection.Descending;
//}
}
#endregion
#region Refresh1Command
public ICommand Refresh1Command
{
get
{
if (_refresh1Command == null)
{
_refresh1Command = new RelayCommand(param => this.Refresh1(),
null);
}
return _refresh1Command;
}
}
private void Refresh1()
{
ViewSource.SortDescriptions.Clear();
_columnName = "firstName";
_sortDirection = ListSortDirection.Descending;
ViewSource.SortDescriptions.Add(new SortDescription(_columnName, _sortDirection));
ViewSource.View.Refresh();
}
#endregion
#region Refresh2Command
public ICommand Refresh2Command
{
get
{
if (_refresh2Command == null)
{
_refresh2Command = new RelayCommand(param => this.Refresh2(),
null);
}
return _refresh2Command;
}
}
private void Refresh2()
{
ViewSource.SortDescriptions.Clear();
ViewSource.SortDescriptions.Add(new SortDescription(_columnName, _sortDirection));
ViewSource.View.Refresh();
}
#endregion
}
}
You can use following styling to get the column header.
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Command"
Value="{Binding DataContext.MyCommand}"/>
<Setter Property="CommandParameter"
Value="{Binding Path=Content, RelativeSource={RelativeSource Self}}"/>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.ColumnHeaderStyle>
You have to create the Command 'MyCommand' in your view model. then as the parameter of your execute method you will get column header name.
I have a xaml page. xaml page wants to show two TextBlocks and one LonglistSelector.
the two TextBlocks datasource come from an object(SpecifiedArticle);the LonglistSelctor itemsSource comes from Collection(ImageUriCollection).
when the page launch, the images cannot be displayed.
two TextBlocks data show well
LonglistSelctor does not show images; but i am sure ImageUriCollection's data can be get from the xaml because i tested in a image control and it works
<Image Source="{Binding ImageUriCollection[0].ImageSource}" Width="108" Height="108" Stretch="UniformToFill">
</Image>
i think the issue is in the LonglistSelctor itemsSource binding. anyone can help?
all code below(without the httpclient wrapper):
DetailsPage.cs is below:
public partial class DetailsPage : PhoneApplicationPage
{
DetailsPageViewModel viewModel = new DetailsPageViewModel();
public DetailsPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(DetailsPage_Loaded);
}
private void DetailsPage_Loaded(object sender, RoutedEventArgs e)
{
DataContext = viewModel;
//imageList.ItemsSource = viewModel.ImageUriCollection;
//imageList.ScrollTo(imageList.ItemsSource[imageList.ItemsSource.Count - 1]);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string ArticleId = "";
try
{
if (NavigationContext.QueryString.TryGetValue("ArticleId", out ArticleId))
{
Debug.WriteLine(ArticleId);
viewModel.LoadPage(Int32.Parse(ArticleId));
//Debug.WriteLine(viewModel.SpecifiedArticle.Words.ToString());
//LayoutRoot.DataContext = new CollectionViewSource { Source = viewModel.SpecifiedArticle };
}
else
{
MessageBox.Show("No ArticleId passed in.");
}
}
catch(Exception ex)
{
MessageBox.Show("Error in DetailsPage.OnNavigatedTo");
}
}
}
ViewModel is below:
public class DetailsPageViewModel : INotifyPropertyChanged
{
private bool _isLoading = false;
public bool IsLoading
{
get
{
return _isLoading;
}
set
{
_isLoading = value;
NotifyPropertyChanged("IsLoading");
}
}
public DetailsPageViewModel()
{
this.SpecifiedArticle = new Article();
this.ImageUriCollection = new ObservableCollection<Photo>();
this.IsLoading = false;
}
private Article specifiedArticle;
public Article SpecifiedArticle
{
get
{
return specifiedArticle;
}
set
{
specifiedArticle = value;
NotifyPropertyChanged("SpecifiedArticle");
}
}
public ObservableCollection<Photo> ImageUriCollection
{
get;
private set;
}
public void LoadPage(int articleId)
{
IsLoading = true;
ReadArticle(articleId);
}
private async void ReadArticle(int articleId)
{
try
{
Article articleDetails = new Article();
articleDetails = await CollectionHttpClient.GetAsyncByArticleId(articleId);
SpecifiedArticle = articleDetails;
//articleDetails.FirstImage = new Uri(articleDetails.ImagePathList[0]);
if (articleDetails.ImagePathList != null)
{
foreach (var item in articleDetails.ImagePathList)
{
Photo p = new Photo();
p.ImageSource = new Uri(item);
this.ImageUriCollection.Add(p);
}
//var image = await CollectionHttpClient.GetImageByImageName(articleDetails.ImagePath);
//Bytelist.Add(image);
}
else
{
this.ImageUriCollection = null;
}
IsLoading = false;
}
catch(Exception ex)
{
MessageBox.Show("sorry, no data.");
IsLoading = false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
xaml is:
<phone:PhoneApplicationPage.Resources>
<vm:DetailsPageViewModel x:Key="viewModel"/>
<phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>
<phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>
<Style x:Key="JumpListStyle" TargetType="phone:LongListSelector">
<Setter Property="LayoutMode" Value="List" />
<Setter Property="Margin" Value="12,12,0,0"/>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource BackgroundConverter}}"
Width="470"
Height="70"
Margin="6">
<TextBlock Text="{Binding Key}"
Foreground="{Binding Converter={StaticResource ForegroundConverter}}"
FontFamily="{StaticResource PhoneFontFamilySemiBold}"
FontSize="28"
Padding="2"
VerticalAlignment="Bottom"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="GroupHeader">
<Border Background="Transparent">
<Border Background="Transparent" BorderBrush="Transparent" BorderThickness="1"
Width="400" Height="90"
HorizontalAlignment="Left">
<TextBlock Text="Pictures:"
Foreground="{StaticResource PhoneAccentBrush}"
FontSize="28"
Padding="2"
FontFamily="{StaticResource PhoneFontFamilySemiLight}"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
</Border>
</Border>
</DataTemplate>
<DataTemplate x:Key="ItemTemplate">
<StackPanel Height="108" Width="108" Margin="6,6">
<Image Width="108" Height="108" Stretch="UniformToFill">
<Image.Source>
<BitmapImage UriSource="{Binding ImageSource}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="{Binding Path=SpecifiedArticle.Subject }" TextWrapping="Wrap" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place images here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Background="Transparent">
<!--
<Image Source="{Binding ImageUriCollection[0].ImageSource}" Width="108" Height="108" Stretch="UniformToFill">
<Image.Source>
<BitmapImage UriSource="{Binding ImageSource}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
-->
<phone:LongListSelector Name="imageList" Margin="13,-30,0,0"
ItemsSource="{Binding ImageUriCollection}"
ItemTemplate="{StaticResource ItemTemplate}"
JumpListStyle="{StaticResource JumpListStyle}"
IsGroupingEnabled="True"
LayoutMode="Grid"
GridCellSize="108,108"/>
</Grid>
<!--ContentPanel - place article words here-->
<StackPanel Grid.Row="2" Margin="12,17,0,28">
<TextBlock Text="{Binding Path=SpecifiedArticle.Words}" TextWrapping="Wrap" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
</Grid>
DetailsPage.cs is below:
public partial class DetailsPage : PhoneApplicationPage
{
DetailsPageViewModel viewModel = new DetailsPageViewModel();
public DetailsPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(DetailsPage_Loaded);
}
private void DetailsPage_Loaded(object sender, RoutedEventArgs e)
{
DataContext = viewModel;
//imageList.ItemsSource = viewModel.ImageUriCollection;
//imageList.ScrollTo(imageList.ItemsSource[imageList.ItemsSource.Count - 1]);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string ArticleId = "";
try
{
if (NavigationContext.QueryString.TryGetValue("ArticleId", out ArticleId))
{
Debug.WriteLine(ArticleId);
viewModel.LoadPage(Int32.Parse(ArticleId));
//Debug.WriteLine(viewModel.SpecifiedArticle.Words.ToString());
//LayoutRoot.DataContext = new CollectionViewSource { Source = viewModel.SpecifiedArticle };
}
else
{
MessageBox.Show("No ArticleId passed in.");
}
}
catch(Exception ex)
{
MessageBox.Show("Error in DetailsPage.OnNavigatedTo");
}
}
}
ViewModel is below:
public class DetailsPageViewModel : INotifyPropertyChanged
{
private bool _isLoading = false;
public bool IsLoading
{
get
{
return _isLoading;
}
set
{
_isLoading = value;
NotifyPropertyChanged("IsLoading");
}
}
public DetailsPageViewModel()
{
this.SpecifiedArticle = new Article();
this.ImageUriCollection = new ObservableCollection<Photo>();
this.IsLoading = false;
}
private Article specifiedArticle;
public Article SpecifiedArticle
{
get
{
return specifiedArticle;
}
set
{
specifiedArticle = value;
NotifyPropertyChanged("SpecifiedArticle");
}
}
public ObservableCollection<Photo> ImageUriCollection
{
get;
private set;
}
public void LoadPage(int articleId)
{
IsLoading = true;
ReadArticle(articleId);
}
private async void ReadArticle(int articleId)
{
try
{
Article articleDetails = new Article();
articleDetails = await CollectionHttpClient.GetAsyncByArticleId(articleId);
SpecifiedArticle = articleDetails;
//articleDetails.FirstImage = new Uri(articleDetails.ImagePathList[0]);
if (articleDetails.ImagePathList != null)
{
foreach (var item in articleDetails.ImagePathList)
{
Photo p = new Photo();
p.ImageSource = new Uri(item);
this.ImageUriCollection.Add(p);
}
//var image = await CollectionHttpClient.GetImageByImageName(articleDetails.ImagePath);
//Bytelist.Add(image);
}
else
{
this.ImageUriCollection = null;
}
IsLoading = false;
}
catch(Exception ex)
{
MessageBox.Show("sorry, no data.");
IsLoading = false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Try this-
just change your ItemTemplate DataTemplate to a simpler one
If it works, add one change at a time.
<DataTemplate x:Key="ItemTemplate">
<Image Source="{Binding ImageSource}" Stretch="UniformToFill"/>
</DataTemplate>
it is the style problem.
delete the style, try again, images show well
<phone:LongListSelector Name="imageList" Margin="13,-30,0,0"
ItemsSource="{Binding ImageUriCollection}"
ItemTemplate="{StaticResource ItemTemplate}"
LayoutMode="Grid"
GridCellSize="108,108">
</phone:LongListSelector>
in the JumpListStyle, it contains the textblock which is not belong to the xaml, that is why the LonglistSelector does not display anything after binding collectly.
I have a DataGrid where each row has a delete button. If I set the Command="Delete" attribute on the Delete button element in XAML, the button is disabled at runtime. Why??
XAML:
<Page x:Class="AxureExport.TargetPage"
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:local="clr-namespace:AxureExport"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"
Title="Define Export Targets"
Loaded="Page_Loaded">
<Page.Resources>
<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="PreviewMouseLeftButtonDown"
Handler="DataGridCell_PreviewMouseLeftButtonDown" />
</Style>
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7" />
<ColumnDefinition Width="65" />
<ColumnDefinition Width="458*" />
<ColumnDefinition Width="47" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="7" />
<RowDefinition Height="63*" />
</Grid.RowDefinitions>
<!-- target file -->
<TextBlock Name="textBlock3"
Text="2. Select the location where you want to save the string files:"
Height="23"
HorizontalAlignment="Left"
Margin="5,0,0,0"
VerticalAlignment="Top"
Grid.Row="2"
Grid.Column="1"
Grid.ColumnSpan="4"
Width="441" />
<TextBlock Name="textBlock4"
Text="(Warning: This tool overwrites files in the target folder.)"
Height="16"
HorizontalAlignment="Left"
Margin="54,15,0,0"
VerticalAlignment="Top"
Width="256"
FontStyle="Italic"
FontWeight="Light"
FontSize="10"
Grid.Row="2"
Grid.Column="1"
Grid.ColumnSpan="2" />
<TextBlock Name="textBlock5"
Text="Target:"
Height="23"
HorizontalAlignment="Left"
Margin="22,30,0,238"
VerticalAlignment="Center"
Grid.Row="1"
Grid.Column="1" />
<!-- ExportTargets Datagrid -->
<DataGrid Name="ExportTargets"
AutoGenerateColumns="False"
Grid.Column="2"
Grid.Row="1"
Margin="0,71,0,63"
ItemsSource="{Binding Path=., Mode=TwoWay}"
SelectionUnit="Cell"
GridLinesVisibility="None"
RowDetailsVisibilityMode="Collapsed"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserResizeRows="False"
RowHeaderWidth="40"
IsSynchronizedWithCurrentItem="True"
HorizontalScrollBarVisibility="Disabled"
CanUserAddRows="True"
CanUserDeleteRows="True">
<DataGrid.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}"
Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}"
Color="Black" />
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridCheckBoxColumn Binding="{Binding IsXML, Mode=TwoWay}"
Header="XML"
CanUserSort="False"
CanUserReorder="False" />
<DataGridCheckBoxColumn Binding="{Binding IsProperty, Mode=TwoWay}"
Header="Property"
CanUserSort="False"
CanUserReorder="False" />
<DataGridTextColumn Binding="{Binding FolderName, Mode=TwoWay}"
Header="Folder"
Width="*"
CanUserReorder="False"
IsReadOnly="False" />
<DataGridTemplateColumn Header="Browse">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="Browse"
Command="{Binding BrowseCommand}"
HorizontalAlignment="Center"
Width="20">...</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Delete" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="Delete"
Command="{x:Static DataGrid.DeleteCommand}"
HorizontalAlignment="Center"
Width="20"
IsEnabled="True">X</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button Name="NextButton"
Content="Next"
Grid.Column="2"
Grid.ColumnSpan="2"
Grid.Row="1"
Margin="0,0,2,12"
Width="100"
Height="40"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Click="NextButton_Click" />
</Grid>
</Page>
Code-behind:
// DataTable
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace AxureExport {
/// <summary>
/// Interaction logic for TargetPage.xaml
/// </summary>
public partial class TargetPage : Page {
FrameWindow _frame;
//ExportTargetInfos _eti;
public TargetPage(FrameWindow frame) {
InitializeComponent();
_frame = frame;
_frame.ExportTargets = new ExportTargetInfos(Properties.Settings.Default.ExportTargetHistory);
this.DataContext = _frame.ExportTargets;
}
//
// enable editing on single-click
private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
DataGridCell cell = sender as DataGridCell;
if (!cell.IsEditing) {
if (!cell.IsFocused)
cell.Focus();
if (!cell.IsSelected)
cell.IsSelected = true;
}
}
private void Page_Loaded(object sender, RoutedEventArgs e) {
}
private void NextButton_Click(object sender, RoutedEventArgs e) {
Properties.Settings.Default.ExportTargetHistory = _frame.ExportTargets.GetExportTargets();
_frame.NavigateTo(typeof(ExportPage));
}
}
}
ViewModel:
using System;
using System.Collections.ObjectModel; // ObservibleCollection<>
using System.Collections.Specialized; // StringCollection
using System.ComponentModel; // INotifyPropertyChanged
namespace AxureExport {
public class ExportTargetInfos : ObservableCollection<ExportTargetInfo> {
const char _SEP = '|'; // field seperator character
// default constructor
public ExportTargetInfos() : base() {
}
// copy constructors
public ExportTargetInfos(ExportTargetInfos etis) : base() {
if (etis == null) return;
foreach (ExportTargetInfo eti in etis) {
this.Add(new ExportTargetInfo(eti.FolderName, eti.IsXML, eti.IsProperty));
}
}
public ExportTargetInfos(StringCollection sc) : base() {
if (sc == null) return;
foreach (string s in sc)
Add(ParseExportTarget(s));
}
public StringCollection GetExportTargets() {
StringCollection sc = new StringCollection();
foreach (ExportTargetInfo et in this)
sc.Add(BuildExportTarget(et));
return sc;
}
// create a string from an ExportTarget (for persistance)
private static string BuildExportTarget(ExportTargetInfo et) {
return et.FolderName + _SEP + et.IsXML.ToString() + _SEP + et.IsProperty.ToString();
}
// create an ExportTarget from an unparsed string (for persistance)
private static ExportTargetInfo ParseExportTarget(string s) {
int count = s.Split(_SEP).Length - 1;
string[] items = s.Split(new[] { _SEP }, StringSplitOptions.None);
string name = (count < 1 ? String.Empty : items[0]);
bool isXML = (count > 0 ? Convert.ToBoolean(items[1]) : false);
bool isProp = (count > 1 ? Convert.ToBoolean(items[2]) : false);
return new ExportTargetInfo(name, isXML, isProp);
}
}
//
// represents an export target (folder plus options) in it's parsed form
public class ExportTargetInfo : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
public IDelegateCommand BrowseCommand { protected set; get; }
// default constructor is needed to enable datagrid to add rows
public ExportTargetInfo() {
_folderName = String.Empty;
_isXML = false;
_isProperty = false;
this.BrowseCommand = new DelegateCommand(ExecuteBrowse, CanExecuteBrowse);
}
public ExportTargetInfo(string targetFolderName, bool isXML, bool isProperties) {
_folderName = targetFolderName;
_isXML = isXML;
_isProperty = isProperties;
this.BrowseCommand = new DelegateCommand(ExecuteBrowse, CanExecuteBrowse);
}
private string _folderName;
public string FolderName {
get { return _folderName; }
set { SetProperty<string>(ref _folderName, value, #"FolderName"); }
}
private bool _isXML;
public bool IsXML {
get { return _isXML; }
set { SetProperty<bool>(ref _isXML, value, #"IsXML"); }
}
private bool _isProperty;
public bool IsProperty {
get { return _isProperty; }
set { SetProperty<bool>(ref _isProperty, value, #"IsProperty"); }
}
// browse button for selected row clicked
void ExecuteBrowse(object param) {
// use WPF-WinForms interop (:-p)
var folderDialog = new System.Windows.Forms.FolderBrowserDialog();
folderDialog.Description = "Please designate the target folder";
folderDialog.SelectedPath = FolderName;
folderDialog.ShowNewFolderButton = true;
if (folderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
FolderName = folderDialog.SelectedPath;
}
bool CanExecuteBrowse(object param) {
return true;
}
protected bool SetProperty<T>(ref T storage, T value, string propertyName = null) {
if (object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged(string propertyName) {
if (PropertyChanged != null)
PropertyChanged( this, new PropertyChangedEventArgs(propertyName));
}
}
}
Does anyone have insight as to what's the cause?
This isn't a solution, but through trial & error I discovered the disabled delete button behavior is caused by the SelectionUnit="Cell" setting in the DataGrid. Setting it to FullRow enables the delete row button.
<Button Name="NextButton" isEnable = "true" />