I am retrieving images from database from particular table. It's showing all images from that table.
Now I need to get that selected image name, it's displaying the name using binding and ToolTip, but I need to get when I click the image, selected image name should be view in message box.
This is my code:
imageView.cs-page.
var query1 = DB_Linq.tbl_ItemMaster.Select(cust => new { cust.Item_Code, cust.Item_Image,cust.ImagePath, cust.ItemName_EN }).ToList();
var QBM1 = (from po in DB_Linq.tbl_ItemMaster
where po.ActiveFlag == true
select new ImageEntity
{
ImagePath = po.ImagePath,
ItemName_EN = po.ItemName_EN
}
);
return QBM1.ToList<ImageEntity>();
ImageEntity.cs
class ImageEntity
{
public String ImagePath
{
get;
set;
}
public String ItemName_EN
{
get;
set;
}
}
Invoice.Xaml.cs-page
private void BindImages()
{
try
{
// Store Data in List Object
List<ImageEntity> ListImageObj = ImageView.GetAllImagesData();
// Check List Object Count
if (ListImageObj.Count > 0)
{
// Bind Data in List Box Control.
LsImageGallery.DataContext = ListImageObj;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
Xaml code is:
<Page.Resources>
<ItemsPanelTemplate x:Key="ListBox_HorizontalItems">
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
<DataTemplate x:Key="ImageGalleryDataTemplate" x:Name="ImageGalleryDataTemplate" >
<Grid>
<Border BorderBrush="ForestGreen" BorderThickness="3" Width="120" Height="120" Padding="10" Margin="15" CornerRadius="10">
<Image Source="{Binding ImagePath}" Stretch="Fill" HorizontalAlignment="Center" >
<Image.ToolTip>
<Grid>
<Image Source="{Binding ImagePath}" Stretch="Fill" HorizontalAlignment="Center" Height="100" Width="100"></Image>
</Grid>
</Image.ToolTip>
</Image>
</Border>
<Border>
<Grid>
<TextBlock Text="{Binding ItemName_EN}" ToolTip="{Binding ItemName_EN}" />
</Grid>
</Border>
<Grid x:Name="LayoutRoot" Background="DarkGreen" >
<Button Click="ButtonClicked" ToolTip="{Binding ItemName_EN}" >
<Image Source="{Binding ImagePath}" Stretch="Fill" Height="100" Width="100" HorizontalAlignment="Center"/>
</Button>
</Grid>
</Grid>
</DataTemplate>
<ItemsPanelTemplate x:Key="ImageGalleryItemsPanelTemplate">
<!--Display Images on UniformGrid Panel-->
<UniformGrid Columns="4" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
</ItemsPanelTemplate>
</Page.Resources>
<Grid>
<ListBox x:Name="LsImageGallery" ItemsSource="{Binding}" ItemTemplate="{DynamicResource ImageGalleryDataTemplate}" ItemsPanel="{DynamicResource ImageGalleryItemsPanelTemplate}">
<ListBox.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black"/>
<GradientStop Color="#FF1E2A2F" Offset="1"/>
</LinearGradientBrush>
</ListBox.Background>
</ListBox>
</Grid>
</Page>
Off the top of my head, you could have a boolean IsSelected property on ImageEntity that is updated by a clicked event in a trigger in the xaml. And you could have DataTrigger in the xaml such shows items when their IsSelected is set to true and hides them otherwise.
<Page.Resources xmlns:conv="clr-namespace:Project.Converters">
<conv:BoolToVisibilityConverter x:Key="boolToVisibilityConverter"/>
<ItemsPanelTemplate x:Key="ListBox_HorizontalItems">
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
<DataTemplate x:Key="ImageGalleryDataTemplate" x:Name="ImageGalleryDataTemplate" >
<Grid>
<Border BorderBrush="ForestGreen" BorderThickness="3" Width="120" Height="120" Padding="10" Margin="15" CornerRadius="10">
<!--Note: You'll Need Antother Event Somewhere In Here To Switch IsSelected Back To False To Hide It Again.-->
<Image Source="{Binding ImagePath}" Stretch="Fill" HorizontalAlignment="Center" MouseDown="MouseDownEventHandler">
<Image.ToolTip>
<Grid>
<Image Source="{Binding ImagePath}" Stretch="Fill" HorizontalAlignment="Center" Height="100" Width="100"></Image>
</Grid>
</Image.ToolTip>
</Image>
</Border>
<Border>
<Grid>
<!--I Added Code Here To Only Show The TextBlock Whenever The IsSelected Property On Your ImageEntity Class Is True-->
<TextBlock Text="{Binding ItemName_EN}" ToolTip="{Binding ItemName_EN}" Visibility="{Binding Path=IsSelected, Converter={StaticResource boolToVisibilityConverter}}" />
</Grid>
</Border>
<Grid x:Name="LayoutRoot" Background="DarkGreen" >
<Button Click="ButtonClicked" ToolTip="{Binding ItemName_EN}" >
<Image Source="{Binding ImagePath}" Stretch="Fill" Height="100" Width="100" HorizontalAlignment="Center"/>
</Button>
</Grid>
</Grid>
</DataTemplate>
<ItemsPanelTemplate x:Key="ImageGalleryItemsPanelTemplate">
<!--Display Images on UniformGrid Panel-->
<UniformGrid Columns="4" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
</ItemsPanelTemplate>
</Page.Resources>
Class ImageEntity : INotifyPropertyChanged
{
private bool isSelected = false;
public String ImagePath
{
get;
set;
}
public String ItemName_EN
{
get;
set;
}
public bool IsSelected
{
get {return isSelected};
set
{
isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
///You Need All Of These To Notify The View That The IsSelected Has Changed So That It Will Update
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public void NotifiyPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
///You Need This To Convert The IsSelected Property Above To A Visibility Enum. This Is Used In Your XAML
namespace Project.Converters
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
/// <summary>
/// TODO: Update summary.
/// </summary>
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value.ToString().ToLower() == "false")
return System.Windows.Visibility.Visible;
else
return System.Windows.Visibility.Collapsed;
//throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
class InVoice
{
private void BindImages()
{
try
{
// Store Data in List Object
List<ImageEntity> ListImageObj = ImageView.GetAllImagesData();
// Check List Object Count
if (ListImageObj.Count > 0)
{
// Bind Data in List Box Control.
LsImageGallery.DataContext = ListImageObj;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
void MouseDownEventHandler(object sender, MouseButtonEventArgs e)
{
//Here You'll Probably Need To Cast sender To A FrameworkElement Or Something In Order To Get The Instance Of The ImageEntity That Was Clicked
//After You Do This, You Can Set The IsSelected Property For The Item To True, And The ItemName_EN Should Automatically Show.
}
}
Related
I have a Windows which contains two Listboxes and one button.
Those two List Box Data Bind to List of Class "ObjectList" and include ObservableCollection in it.
The First ListBox (we will call it "ObjectLists") contain text box in it.
The Second ListBox (we will call it "ObjectListsSelected") contain Listbox in it.
I use those top Listboxes to get dynamic UI.
The Button executea a command which use to split the text in the first listbox (follow \r\n chars), add them to the second list box and clear the Text Box in first listbox.
I'm having a problem with Data Binding for "ObjectLists".
The Clean option doen't reflect in the UI although the property get this update.
When Debugging this scenario i found out that the Clear action doesn't go to the set of the property.
of course i Used Property Change, but nothing work.
Main Windows
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:ListToTextConverter x:Key="converter1"></local:ListToTextConverter>
</Window.Resources>
<Grid Name="ObjPanel">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="Object" Height="30"/>
<ListBox Name="ObjectLists" Grid.Row="1" Grid.Column="0" ItemsSource="{Binding OB1,Mode=TwoWay}" BorderThickness="0" Background="Transparent" Width="200" HorizontalAlignment="Center">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Name="ObjectList" Text="{Binding content,Mode=TwoWay,Converter={StaticResource converter1}}" Margin="0,0,30,0" Height="225" Width="200" HorizontalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Name="AddButton" Command="{Binding AddCommand}" Grid.Row="1" Grid.Column="1" Height="50" Width="150" HorizontalAlignment="Center" Margin="0,0,10,0">Add</Button>
<Label Content="ObjectSelect" Height="30" Grid.Column="2"/>
<!--<ListBox Name="ObjectListSelectedBox1" ItemsSource="{Binding ObjSelected}" Grid.Row="1" Grid.Column="3" Width="200" Height="225" HorizontalAlignment="Center"/>-->
<ListBox Name="ObjectListsSelected" Grid.Row="1" Grid.Column="2" ItemsSource="{Binding OB2,Mode=TwoWay}" BorderThickness="0" Background="Transparent" Width="200" HorizontalAlignment="Center">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<ListBox Name="ObjectListSelected" ItemsSource="{Binding content,Mode=TwoWay}" Margin="0,0,30,0" Height="225" Width="200" HorizontalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
class ObjectList
class ObjectList
{
public string header { get; set; }
private ObservableCollection<string> _content;
public ObservableCollection<string> content
{
get { return _content; }
set
{
_content = value;
}
}
public ObjectList()
{
content=new ObservableCollection<string>();
}
}
Main View Model
class MainVM : INotifyPropertyChanged
{
public RelayCommand AddCommand { get; set; }
public List<ObjectList> OB2 { get; set; }
private List<ObjectList> ob1;
public List<ObjectList> OB1
{
get { return ob1; }
set {
ob1 = value;
OnPropertyChanged(nameof(ob1));
}
}
public MainVM()
{
this.AddCommand = new RelayCommand(Add);
OB1 = new List<ObjectList>()
{
new ObjectList()
};
OB2 = new List<ObjectList>()
{
new ObjectList()
};
}
public void Add()
{
foreach (var s in OB1[0].content)
{
OB2[0].content.Add(s);
}
OB1[0].content.Clear();
OnPropertyChanged(nameof(OB1));
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
Covertors
public class ListToTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
StringBuilder sb = new StringBuilder();
Type TEST = value.GetType();
foreach (string s in (ObservableCollection<string>)value) sb.AppendLine(s);
string str = sb.ToString();
return str;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string[] lines = Regex.Split((string)value, "\r\n");
ObservableCollection<string> OC = new ObservableCollection<string>(lines);
return (OC);
}
}
In first column i have list of groups ("First","Second"). In second column i have 5 button's. I want to enable or disable group of button's after choosing their group in first column. How to do this in MVVM pattern?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Data();
}
}
public class Data
{
public List<string> Items { get; set; }
public Data()
{
Items = new List<string>();
Items.Add("First");
Items.Add("Second");
}
}
Xaml:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding Items}" Grid.Column="0">
<ListView.ItemTemplate>
<DataTemplate>
<Label Content="{Binding .}"></Label>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="First" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="21,24,0,0" VerticalAlignment="Top" Width="76" IsEnabled="False"/>
<Button Content="Second" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="102,48,0,0" VerticalAlignment="Top" Width="76" IsEnabled="True"/>
<Button Content="First" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="33,83,0,0" VerticalAlignment="Top" Width="76" IsEnabled="False"/>
<Button Content="Second" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="126,93,0,0" VerticalAlignment="Top" Width="76" IsEnabled="True" RenderTransformOrigin="1.088,-0.075"/>
<Button Content="Second" Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="93,186,0,0" VerticalAlignment="Top" Width="76" IsEnabled="True"/>
</Grid>
Create your VM classes like:
public class Data:INotifyPropertyChanged
{
public ObservableCollection<MyRecord> Items
{
get{
return _items;
}
set{
_items=value;
OnProperyChanged("Items")
}
}
public Data()
{
Items = new ObservableCollection<MyRecord>()
{
new MyRecord(){Title:"First",IsEnable:false}),
new MyRecord(){Title:"Second",IsEnable:false})
};
}
//---------------------------------------------------------------
public event PropertyChangedEventHandler PropertyChanged;
private void OnProperyChanged(string propertyName)
{
if (PropertyChanged != null)
{
var handler= PropertyChanged ;
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class MyRecord:INotifyPropertyChanged
{
private int _title;
private bool _isEnable;
public int Title
{
get
{
return _title;
}
set
{
_title= value;
OnProperyChanged("Title")
}
}
public bool IsEnable
{
get
{
return _isEnable;
}
set
{
_isEnable= value;
OnProperyChanged("IsEnable")
}
}
//---------------------------------------------------------------
public event PropertyChangedEventHandler PropertyChanged;
private void OnProperyChanged(string propertyName)
{
if (PropertyChanged != null)
{
var handler= PropertyChanged ;
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Now in your Xaml bind the IsEnabled property of each Button to appropriate property...
You can write the following code with BooleanToVisibilityConverter:
//First add BooleanToVisibilityConverter to the window resources
// When you know Items[0] is FIRST use some code like this>>
IsEnabled="{Binding Items[0].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Sample:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding Items}" Grid.Column="0">
<ListView.ItemTemplate>
<DataTemplate>
<Label Content="{Binding .}"></Label>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="First"
IsEnabled="{Binding Items[0].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="21,24,0,0" VerticalAlignment="Top" Width="76"/>
<Button Content="Second"
IsEnabled="{Binding Items[1].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="102,48,0,0" VerticalAlignment="Top" Width="76"/>
<Button Content="First"
IsEnabled="{Binding Items[0].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="33,83,0,0" VerticalAlignment="Top" Width="76"/>
<Button Content="Second"
IsEnabled="{Binding Items[1].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="126,93,0,0" VerticalAlignment="Top" Width="76" RenderTransformOrigin="1.088,-0.075"/>
<Button Content="Second"
IsEnabled="{Binding Items[1].IsEnable, converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Column="1" HorizontalAlignment="Left" Height="30" Margin="93,186,0,0" VerticalAlignment="Top" Width="76"/>
</Grid>
OK, every things is good until this step. Now if you make IsEnable property of each item to TRUE, then the buttons must be Enabled And conversely. To perform it you can:
Write a Command in your Data class and make a binding between each List
item and the command.
Use ListView.SelectionChanged event to make IsEnable property of the Clicked item to TRUE. Note: Now, the type of each item in the ListView is MyRecord.
The best solution to your problem is to use a IValueConverter, in this example I created a convert named GroupToBooleanConverter receiving the value of the selected item in the first column by the parameter value and the button group by parameter 'parameter ', the code converter is below:
public class GroupToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var selectedGroup = value as string;
var buttonGroup = (string)parameter;
return buttonGroup.Equals(selectedGroup);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Now in its XAML you must reference the namespace of your turn, in my example the namespace convert is namespaceOfConverter, and must be imported to convert through it, is as follows:
xmlns:converters="clr-namespace:namespaceOfConverter"
Place the attribute up on your Window tag in your XAML. Now you must reference the convert, putting it in the Window resources:
<Window.Resources>
<converters:GroupToBooleanConverter x:Key="GroupToBoolean" />
</Window.Resources>
I called your ListView of lsvGroups:
<ListView ItemsSource="{Binding Items}" x:Name="lsvGroups" Grid.Column="0">
....
Now just use the converter in your buttons, performing binding in the property IsEnabled:
IsEnabled="{Binding SelectedItem, ElementName=lsvGroups,Converter={StaticResource GroupToBoolean},ConverterParameter=First}"
OBs: In the place of First you put the name of group associate with button.
I'm in the process of converting a fairly large WPF app from three-layer into MVVM, and in the process learning MVVM. So far, I haven't delved into too much detail around Bindings (etc), so bear with me.
I'm trying to bind the System.Windows.Visibility of multiple controls to a public property ("State") of the ViewModel. When the parent TabItem loads, the State property is read and handled as desired. When subsequent changes to the property are made, however, they appear to be ignored. I've (re-re-re-)checked Bindings, debugged the Converters, etc, and this is driving me crazy.
ViewModel:
public class MarketingListViewModel: IDisposable, INotifyPropertyChanged
{
private UiState state;
public event PropertyChangedEventHandler PropertyChanged;
public UiState State
{
get { return state; }
set
{
if (state != value)
{
state = value;
NotifyPropertyChanged("State");
}
}
}
public MarketingListViewModel()
{
State = UiState.View;
}
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
View:
<UserControl 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:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
mc:Ignorable="d" x:Class="WpfCrm.tabListManager" xmlns:DPH="clr-namespace:DPH" >
<UserControl.Resources>
<DPH:MarketingListViewModel x:Key="listVM" />
<!-- Note that the above line is giving me an "Object reference not set to an instance of an object" error -->
</UserControl.Resources>
<Grid x:Name="gridMain" DataContext="{StaticResource listVM}" >
<Border Grid.Row="0" Grid.Column="1" Margin="10"
Style="{StaticResource WidgetStyle}" >
<Grid x:Name="gridListManagement" >
<Label x:Name="labelManageLists" Content="Manage Lists" MouseDown="labelManageLists_MouseDown"
Style="{StaticResource WidgetTitleStyle}"
Grid.Row="0" Grid.Column="0" />
<StackPanel Grid.Row="0" Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Right" >
<Label x:Name="llNewList" Content="new" MouseDown="llNewList_MouseDown"
Style="{StaticResource LinkLabelStyle}"
HorizontalAlignment="Right" />
<Label x:Name="llCloseManageLists" Content="close" MouseDown="llCloseManageLists_MouseDown"
Style="{StaticResource LinkLabelStyle}"
HorizontalAlignment="Right" />
</StackPanel>
<Label x:Name="labelListName" Content="Name" Grid.Row="1" Grid.Column="0" />
<Grid Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" >
<ComboBox x:Name="cbLists" SelectedIndex="-1" SelectionChanged="cbLists_SelectionChanged" IsReadOnly="True"
ItemsSource="{Binding Path=AllMarketingLists}"
DisplayMemberPath="Name"
SelectedValuePath="Id"
Visibility="{Binding Path=State, Converter={StaticResource ViewStateToVisibilityConverter} }"/>
<TextBox x:Name="tbListName"
Text="{Binding Path=OList.Name}"
Visibility="{Binding Path=State, Converter={StaticResource EditStateToVisibilityConverter} }"/>
</Grid>
<Label x:Name="labelListDescription" Content="Description" Grid.Row="2" Grid.Column="0" />
<Grid Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" >
<TextBlock x:Name="textblockListDescription" TextWrapping="Wrap"
Text="{Binding Path=OList.Notes}"
Visibility="{Binding Path=State, Converter={StaticResource ViewStateToVisibilityConverter} }"
Grid.ColumnSpan="2" />
<TextBox x:Name="tbListDescription" TextWrapping="Wrap"
Text="{Binding Path=OList.Notes}"
Visibility="{Binding Path=State, Converter={StaticResource EditStateToVisibilityConverter} }"
Grid.ColumnSpan="2" />
</Grid>
<StackPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" HorizontalAlignment="Right" Orientation="Horizontal" >
<Button x:Name="buttonEditList" Content="Edit" Click="buttonEditList_Click"
Visibility="{Binding Path=State, Converter={StaticResource ViewStateToVisibilityConverter} }"
Width="60" Margin="3" />
<Button x:Name="buttonSaveList" Content="Save" Click="buttonSaveList_Click"
Visibility="{Binding Path=State, Converter={StaticResource EditStateToVisibilityConverter} }"
Width="60" Margin="3" />
<Button x:Name="buttonCancel" Content="Cancel" Click="buttonCancel_Click"
Visibility="{Binding Path=State, Converter={StaticResource EditStateToVisibilityConverter} }"
Width="60" Margin="3" />
</StackPanel>
</Grid>
</Border>
</Grid>
And the code-behind has a few methods like:
private void buttonEditList_Click(object sender, RoutedEventArgs e)
{
listVM.State = UiState.Edit;
}
Does anyone have ideas on why the controls aren't updating their visibility after the State change?
Kind thanks,
DPH
EDIT -- Converters:
[ValueConversion(typeof(WpfCrm.UiState), typeof(System.Windows.Visibility))]
public class EditStateToVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
UiState state = (UiState)value;
if (state == UiState.View) return Visibility.Collapsed;
else return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
[ValueConversion(typeof(WpfCrm.UiState), typeof(System.Windows.Visibility))]
public class ViewStateToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
UiState state = (UiState)value;
if (state == UiState.View) return Visibility.Visible;
else return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
You seem to be used two different instances of your view model, one declared and used in XAML
<UserControl.Resources>
<DPH:MarketingListViewModel x:Key="listVM" />
</UserControl.Resources>
<Grid DataContext="{StaticResource listVM}" >
and one in code-behind (from comment):
listVM = new MarketingListViewModel();
You should of course be using only one. So change your code behind declaration to
listVM = (MarketingListViewModel)Resources["listVM"];
OK, there is a mistake. You declare listVM as
var listVM = new MarketingListViewModel();
But this is not the listVM from your XAML. In XAML you have created another instance of MarketingListViewModel. So, when you try to change listVM that was declared in code, nothing happens because this object is not DataContext of your Grid.
In your Click handler you have to write the following:
private void buttonEditList_Click(object sender, RoutedEventArgs e)
{
var _listVM = (MarketingListViewModel)FindResource("listVM");
_listVM.State = UiState.Edit;
}
OR replace your listVM declaration in code-behind with this one:
listVM = (MarketingListViewModel)FindResource("listVM");
Then you won't need to change event handlers.
Hope, it helps.
I am trying to build a diary app that uses hub as user interface and update the UI after saving the diary. I already implemented the INotifyPropertyChanged but it didn't work. I want the item that is added after saving to appear on the hub immediately.
public class SampleDataGroup : INotifyPropertyChanged
{
public SampleDataGroup()
{
UniqueId = string.Empty;
Title = string.Empty;
Subtitle = string.Empty;
Description = string.Empty;
ImagePath = string.Empty;
Items = new ObservableCollection<DiaryData>();
}
public string UniqueId { get; private set; }
public string Title { get; private set; }
public string Subtitle { get; private set; }
public string Description { get; private set; }
public string ImagePath { get; private set; }
private ObservableCollection<DiaryData> _items;
public ObservableCollection<DiaryData> Items { get{return _items;} private set
{
OnPropertyChanged("Items");
_items = value;
} }
public override string ToString()
{
if (this.Title != null)
{
return this.Title;
}
else
{
System.Diagnostics.Debug.WriteLine("this is null at tostring");
return null;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
public sealed class SampleDataSource : INotifyPropertyChanged
{
private static SampleDataSource _sampleDataSource = new SampleDataSource();
private ObservableCollection<SampleDataGroup> _groups = new ObservableCollection<SampleDataGroup>();
public ObservableCollection<SampleDataGroup> Groups
{
get { return this._groups; }
set { }
}
public static async Task<IEnumerable<SampleDataGroup>> GetGroupsAsync()
{
await _sampleDataSource.GetSampleDataAsync();
return _sampleDataSource.Groups;
}
public static async Task<SampleDataGroup> GetGroupAsync(string uniqueId)
{
System.Diagnostics.Debug.WriteLine("GetGroupAsync is entered phase 1");
await _sampleDataSource.GetSampleDataAsync();
// Simple linear search is acceptable for small data sets
System.Diagnostics.Debug.WriteLine("GetGroupAsync is entered phase 2");
var matches = _sampleDataSource.Groups.Where((group) => group.UniqueId.Equals(uniqueId));
if (matches.Count() == 1) return matches.First();
return null;
}
public static async Task<DiaryData> GetItemAsync(string uniqueId)
{
await _sampleDataSource.GetSampleDataAsync();
System.Diagnostics.Debug.WriteLine("GetItemAsync is entered");
// Simple linear search is acceptable for small data sets
var matches = _sampleDataSource.Groups.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
if (matches.Count() == 1) return matches.First();
else return null;
}
private async Task GetSampleDataAsync()
{
System.Diagnostics.Debug.WriteLine("GetSampleDataAsync is entered");
//if (this._groups.Count != 0)return;
Uri dataUri = new Uri("ms-appdata:///local/data.json");
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(dataUri);
string jsonText = await FileIO.ReadTextAsync(file);
JsonArray jsonArray = JsonArray.Parse(jsonText);
SampleDataGroup group = new SampleDataGroup();
foreach (JsonValue itemValue in jsonArray)
{
JsonObject itemObject = itemValue.GetObject();
group.Items.Add(new DiaryData(itemObject["Title"].GetString(),
itemObject["Content"].GetString(),
itemObject["Coordinate"].GetString(),
itemObject["UniqueId"].GetString(),
itemObject["ImagePath"].GetString(),
itemObject["VideoPath"].GetString()));
System.Diagnostics.Debug.WriteLine(itemObject["Title"].GetString());
}
this.Groups.Add(group);
System.Diagnostics.Debug.WriteLine("GetSampleDataAsync is finished");
}
//}
public event PropertyChangedEventHandler PropertyChanged;
}
here's my XAML File
<Page
x:Class="DiaryAppHub.HubPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DiaryAppHub"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:DiaryAppHub.Data"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
d:DataContext="{Binding Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:data.json}}"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="HubSectionHeaderTemplate">
<TextBlock Margin="0,0,0,-9.5" Text="{Binding}"/>
</DataTemplate>
<!-- Grid-appropriate item template as seen in section 2 -->
<DataTemplate x:Key="Standard200x180TileItemTemplate">
<Grid Margin="0,0,9.5,9.5" Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" Height="138.5" Width="138.5"/>
<TextBlock Text="{Binding Title}" VerticalAlignment="Bottom" Margin="9.5,0,0,6.5" Style="{ThemeResource BaseTextBlockStyle}"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="StandardTripleLineItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,9.5,0,0" Grid.Column="0" HorizontalAlignment="Left">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" Height="79" Width="79"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}"/>
<TextBlock Text="{Binding Description}" Style="{ThemeResource ListViewItemContentTextBlockStyle}" Foreground="{ThemeResource PhoneMidBrush}" />
<TextBlock Text="{Binding Subtitle}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" />
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="StandardDoubleLineItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,9.5,0,0" Grid.Column="0" HorizontalAlignment="Left">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" Height="79" Width="79"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}" Foreground="Black"/>
<TextBlock Text="{Binding Subtitle}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" Foreground="DimGray"/>
</StackPanel>
</Grid>
</DataTemplate>
</Page.Resources>
<Page.BottomAppBar>
<CommandBar Background="Transparent">
<AppBarButton Icon="Add" Label="Add" Click="add_onclick"/>
<AppBarButton Icon="Add" Label="Shake it!" />
</CommandBar>
</Page.BottomAppBar>
<Grid x:Name="LayoutRoot">
<Hub x:Name="Hub" x:Uid="Hub" Header="diary app hub" Margin="0,0,0,-59" Foreground="DimGray">
<Hub.Background>
<ImageBrush ImageSource="ms-appx:/Assets/desk_paper.png" Stretch="None"/>
</Hub.Background>
<!--<HubSection x:Uid="HubSection1" Header="SECTION 1" DataContext="{Binding Groups}" HeaderTemplate="{ThemeResource HubSectionHeaderTemplate}">
<DataTemplate>
<ListView
ItemsSource="{Binding}"
IsItemClickEnabled="True"
ItemClick="GroupSection_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,27.5">
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</HubSection>-->
<HubSection x:Uid="HubSection5" Header="Recent"
DataContext="{Binding Groups[0]}" HeaderTemplate="{ThemeResource HubSectionHeaderTemplate}">
<DataTemplate>
<ListView
AutomationProperties.AutomationId="ItemListViewSection5"
AutomationProperties.Name="Items In Group"
SelectionMode="None"
IsItemClickEnabled="True"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource StandardDoubleLineItemTemplate}"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
</ListView>
</DataTemplate>
</HubSection>
<HubSection x:Uid="HubSection2" Header="All notes" Width ="Auto"
DataContext="{Binding Groups[0]}" HeaderTemplate="{ThemeResource HubSectionHeaderTemplate}" Height="659" >
<DataTemplate>
<GridView
Margin="0,9.5,0,0"
ItemsSource="{Binding Items}"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Items In Group"
ItemTemplate="{StaticResource Standard200x180TileItemTemplate}"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</DataTemplate>
</HubSection>
</Hub>
</Grid>
You need to raise the PropertyChanged event for the model's properties. The UI doesn't get notified as properties like Title,Subtitle don't raise the PropertyChanged event when they are modified. It should be like this:
private string _title;
public string Title
{
get
{
return _title;
}
set
{
if(_title!=value)
{
_title=value;
OnPropertyChanged("Title");
}
}
}
Do this similarly for other properties. Also, you don't need to raise the PropertyChanged event for an ObservableCollection as an ObservableCollection implements INotifyPropertyChanged by default.
In my app I load image and verify I haven't too much blobs.
In additional, I put all images I loaded in list box and all image have a border.
Now, I want to change border color pet item according the Boolean value (true or false according numbers of blobs and their size).
If my image passed the border should be green, else red.
my relevent code:
public List<String> ImagePath = new List<String>();
public MainWindow()
{
InitializeComponent();
lb_Images.ItemsSource = ImagePath;
}
private void bu_addImage_Click(object sender, RoutedEventArgs e)
{
addImageToListBox();
}
private void addImageToListBox()
{
String imagePath = getImage();
// verfiy img haven't too much blobs
Boolean passed = imagePassed(imagePath);
// add the image to the list box
// I want to change border according passed value
// True - green; False- red.
ImagePath.Add(imagePath);
lb_Images.Items.Refresh();
}
XAML:
<Window x:Class="forQuestionWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="216" Width="519">
<Window.Resources>
<DataTemplate x:Key="ImageGalleryDataTemplate">
<Grid>
<Border BorderBrush="Green" BorderThickness="2" Width="120" Height="120" Padding="5" Margin="5" CornerRadius="6">
<Image Source="{Binding}" Stretch="Fill" HorizontalAlignment="Center">
<Image.ToolTip>
<Grid>
<Image Source="{Binding}" Stretch="Fill" HorizontalAlignment="Center" Height="200" Width="200" />
</Grid>
</Image.ToolTip>
</Image>
</Border>
</Grid>
</DataTemplate>
<ItemsPanelTemplate x:Key="ImageGalleryItemsPanelTemplate">
<UniformGrid Rows="1" Columns="25" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
</ItemsPanelTemplate>
</Window.Resources>
<Grid>
<Canvas Height="177" HorizontalAlignment="Left" Name="canvas1" VerticalAlignment="Top" Width="497">
<ListBox Canvas.Left="6" Canvas.Top="5" Height="166" Name="lb_Images" Width="441"
ItemTemplate="{StaticResource ImageGalleryDataTemplate}"
ItemsSource="{Binding Path=ImagePath}"
ItemsPanel="{StaticResource ImageGalleryItemsPanelTemplate}">
</ListBox>
<Button Canvas.Left="453" Canvas.Top="26" Content="Add" Height="64" Name="bu_addImage" Width="38" Click="bu_addImage_Click" />
</Canvas>
</Grid>
</Window>
For example, in the below image latest two items need to be with red border:
Thank you on any help!
AsfK
Instead of binding to imagePath (string) you can define a class:
public class ImageStuff {
public string ImagePath {get; set;}
public bool Passed {get; set;}
}
and add instance of this to the listbox.
Then, you can use a converter for your border like this:
<Border BorderThickness="2" Width="120" Height="120" Padding="5" Margin="5" CornerRadius="6" BorderBrush="{Binding Path=Passed, Mode=OneWay, Converter={StaticResource borderConverter}}">
where borderConverter is something like this:
public class borderConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (value is bool)
{
if (!(bool)value == true)
return new SolidColorBrush(Colors.Red);
}
return new SolidColorBrush(Colors.Green);
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw NotImplementedException();
}
}
You have to include borderConverter in your resources like this:
<Window.Resources>
<src:borderConverter x:Key="borderConverter" />
</Window.Resources>
where src is the namespace.
If you want to change property of ImageStuff class dinamically you have to implement INotifyPropertyChanged so the binding will be updated.
You can do it without Converter, just add DataTrigger with Tag property to DataTemplate. This can affect to the performance because the Converter will work little much longer.
Add this class:
public class MyImage
{
public string ImagePath
{
get;
set;
}
public bool Flag
{
get;
set;
}
}
And in code-behind use like this:
public List<MyImage> ImagePath = new List<MyImage>();
Full example:
XAML
<DataTemplate x:Key="ImageGalleryDataTemplate">
<Grid>
<Border Name="MyBorder" BorderBrush="#FFFF9800" BorderThickness="1" Width="120" Height="120" Padding="5" Margin="5" CornerRadius="6">
<Image Name="MyImage" Tag="{Binding Path=Flag}" Source="{Binding Path=ImagePath}" Stretch="Fill" HorizontalAlignment="Center">
<Image.ToolTip>
<Grid>
<Image Source="{Binding Path=ImagePath}" Stretch="Fill" HorizontalAlignment="Center" Height="200" Width="200" />
</Grid>
</Image.ToolTip>
</Image>
</Border>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Tag, ElementName=MyImage}" Value="True">
<Setter TargetName="MyBorder" Property="BorderBrush" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Tag, ElementName=MyImage}" Value="False">
<Setter TargetName="MyBorder" Property="BorderBrush" Value="Green" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Code-behind
public partial class MainWindow : Window
{
int imageNumber = 0;
public List<MyImage> ImagePath = new List<MyImage>();
public MainWindow()
{
InitializeComponent();
lb_Images.ItemsSource = ImagePath;
}
private void bu_addImage_Click(object sender, RoutedEventArgs e)
{
addImageToListBox();
}
private void addImageToListBox()
{
imageNumber++;
if (imageNumber == 4) imageNumber = 0;
string directoryPath = AppDomain.CurrentDomain.BaseDirectory;
// load input image
string ImageFilename = directoryPath + "img";
ImageFilename += imageNumber.ToString();
ImageFilename += ".jpg";
ImagePath.Add(new MyImage
{
ImagePath = ImageFilename,
Flag = false
});
lb_Images.Items.Refresh();
}
}
public class MyImage
{
public string ImagePath
{
get;
set;
}
public bool Flag
{
get;
set;
}
}
In order to the properties of MyImage class successfully changed, you need to implement the INotifyPropertyChanged interface.
You neeed to write BoolToColorConverter for this purpose. Find following converter code.
public sealed class BoolToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool bValue = (bool)value;
if (bValue)
return Color.Green;
else
return Color.Red;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Color color = (Color)value;
if (color == Color.Green)
return true;
else
return false;
}
}