I have a problem with control visibility in listbox itemtemplate. Following is my code to bind data to Visibility property of imagetools:AnimatedImage and Textblock in xaml:
<ListBox x:Name="listSellers" ItemsSource="{Binding TagList}" SelectionChanged="listSellers_SelectionChanged" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,12,0,12" Height="132">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="107"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Margin="0,0,-2,8">
<Grid>
<imagetools:AnimatedImage Source="{Binding Seller.Logo, Converter={StaticResource ImageConverter}}" Stretch="Uniform" Width="240" Template="{StaticResource AnimatedImageControlTemplate1}" Visibility="{Binding LogoVisibility}"/>
<TextBlock x:Name="sellerNameTxtBlock" TextWrapping="Wrap" Text="{Binding Seller.Name}" FontSize="24" FontFamily="Segoe WP" Margin="10,0,0,0" Foreground="#FF354F59" Height="41" Visibility="{Binding Path=SellerNameVisibility}"/>
</Grid>
</Border>
<StackPanel Grid.Column="1" Orientation="Vertical">
<!--<TextBlock TextWrapping="Wrap" Text="{Binding Seller.Name}" FontSize="24" FontFamily="Segoe WP" Margin="10,0,0,0" Foreground="#FF354F59" Height="41"/>-->
<!--<TextBlock TextWrapping="Wrap" Text="amazon.com" FontSize="16" FontFamily="Segoe WP" Margin="10,0,0,0" Foreground="#FF157CCC" Height="35"/>-->
<TextBlock TextWrapping="Wrap" Text="{Binding TotalPrice}" FontSize="21.333" FontFamily="Segoe WP Semibold" Margin="10,0,0,0" Foreground="#cc4225"/>
<TextBlock FontSize="{StaticResource PhoneFontSizeSmall}" Text="{Binding Price}" Margin="10,0,0,0" Foreground="#FF354F59"/>
<TextBlock FontSize="{StaticResource PhoneFontSizeSmall}" Text="{Binding Tax}" Margin="10,0,0,0" Foreground="#FF354F59"/>
<TextBlock FontSize="{StaticResource PhoneFontSizeSmall}" Text="{Binding Shipping}" Margin="10,0,0,0" Foreground="#FF354F59"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Following is the declaration of the property in view model:
public Visibility LogoVisibility
{
get { return (Visibility)GetValue(LogoVisibilityProperty); }
set { SetValue(LogoVisibilityProperty, value); }
}
// Using a DependencyProperty as the backing store for LogoVisibility. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LogoVisibilityProperty =
DependencyProperty.Register("LogoVisibility", typeof(Visibility), typeof(ProductDetailViewModel), new PropertyMetadata(Visibility.Collapsed));
public Visibility SellerNameVisibility
{
get { return (Visibility )GetValue(SellerNameVisibilityProperty); }
set { SetValue(SellerNameVisibilityProperty, value); }
}
// Using a DependencyProperty as the backing store for SellerNameVisibility. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SellerNameVisibilityProperty =
DependencyProperty.Register("SellerNameVisibility", typeof(Visibility), typeof(ProductDetailViewModel), new PropertyMetadata(Visibility.Collapsed));
Following is where I set Visibility in view model:
foreach (Tag tag in tagArray)
{
if (tag.Seller.Logo.Equals(""))
{
tag.Seller.Logo = "Images/NoImageFound.png";
LogoVisibility = Visibility.Collapsed;
SellerNameVisibility = Visibility.Visible;
}
else
{
LogoVisibility = Visibility.Visible;
SellerNameVisibility = Visibility.Collapsed;
}
tag.Price = "Base: " + tag.Price;
if (tag.Tax == null)
{
tag.Tax = "Tax: N/A";
}
else
{
tag.Tax = "Tax: " + tag.Tax;
}
if (tag.Shipping == null)
{
tag.Shipping = "Ship: N/A";
}
else
{
tag.Shipping = "Ship: " + tag.Shipping;
}
tempTagList.Add(tag);
}
TagList = tempTagList;
}
And here's where I set the datacontext in code behind:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
_productDetailViewModel = new ProductDetailViewModel();
DataContext = _productDetailViewModel;
string productTitleId = "";
if (NavigationContext.QueryString.TryGetValue("productTitleId", out productTitleId))
{
_productTitleId = productTitleId;
_productDetailViewModel.getProductDetailFromServer(_productTitleId, "");
}
}
I also do some other data bindings in these files, all of them work. Only this Visibility binding fails. Really don't know why. =( Any ideas? Thanks!!!
Looks like your ListBox ItemsSource is bound to a collection of "Tag" objects. This means that each ListBoxItem would be bound to a "Tag" object. So, the DataTemplate you are creating has a DataContext equal to one Tag object. I do not see that LogoVisibility is on the Tag object. It looks like it is on the object that holds a reference to the tag list. Going this route, you would want the LogoVisibility and NameVisibility on the Tag object itself.
What I would suggest is to not put that logic into your model object (Tag) and instead have a ValueConverter to handle this logic.
public class EmptyToVisibilityConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null) return Visibility.Collapsed;
string val = value.ToString();
return string.IsNullOrWhiteSpace(val) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Then change your Visibility bindings to:
<Grid DataContext="{Binding Seller}">
<imagetools:AnimatedImage Source="{Binding Logo, Converter={StaticResource ImageConverter}}"
Stretch="Uniform" Width="240"
Template="{StaticResource AnimatedImageControlTemplate1}"
Visibility="{Binding Logo, Converter={StaticResource EmptyToVis}}"/>
<TextBlock x:Name="sellerNameTxtBlock" TextWrapping="Wrap" Text="{Binding Name}" FontSize="24"
FontFamily="Segoe WP" Margin="10,0,0,0" Foreground="#FF354F59" Height="41"
Visibility="{Binding Name, Converter={StaticResource EmptyToVis}}"/>
</Grid>
Related
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.
To start off, I have a listbox that is trying to accept a UserControl as the DataTemplate:
<ListBox VerticalAlignment="Stretch" Name="GeneralMcmView" Grid.Column="0" HorizontalAlignment="Stretch" >
<ListBox.ItemTemplate>
<DataTemplate DataType="local:GeneralMcmMessage">
<local:GeneralMcmMessage />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
With the contents of the usercontrol looking like:
<ContentControl FontFamily="Segoe UI" VerticalAlignment="Stretch" FontSize="10">
<Grid VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="0">
<TextBlock Name="MessageDateTime" Text="{Binding ElementName=_this, Path=TimeStamp, StringFormat=MM/dd/yyyy h:mm:ss.fff tt \'GMT\' (zzz)}" />
<TextBlock Name="MessageTypeLabel" Margin="15,0,5,0" Text="Type:"/>
<TextBlock Name="MessageType" Text="{Binding ElementName=_this, Path=Type}" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="1">
<TextBlock Name="MessageNameLabel" Margin="0,0,5,0" Text="Message Name:" />
<TextBlock Name="MessageNameValue" Text="{Binding ElementName=_this, Path=MessageName}" TextWrapping="Wrap" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Vertical" Grid.Row="2">
<TextBlock Name="MessageLabel" Text="Message:"/>
<TextBlock Name="Message" Margin="10,0,0,0" Text="{Binding ElementName=_this, Path=MessageContent}" />
</StackPanel>
</Grid>
</ContentControl>
I then create a couple messages, all with different data (The Listbox's ItemSource is bound to the GeneralMessages ObservableCollection):
GeneralMcmMessage newMsg = new GeneralMcmMessage()
{
MessageId = e.McmMessageViewInfo.Id,
TimeStamp = e.McmMessageViewInfo.MessageDateTime,
Type = e.McmMessageViewInfo.MessageType.ToString(),
MessageName = e.McmMessageViewInfo.MessageName,
MessageContent = e.McmMessageViewInfo.Message.ToString()
};
GeneralMessages.Add( newMsg );
During runtime I interrogate the Items property of the listbox and all the data looks correct, however all I see in the listbox are entries of the GeneralMcmMessage User Control with default data values. Any ideas as to why?
Also, FWIW I am using INotifyPropertyChanged in the usercontrol class:
public partial class GeneralMcmMessage : UserControl, INotifyPropertyChanged
{
private Constants.PiuModule piuModule = Constants.PiuModule.MCM;
private string className = "GeneralMcmMessage";
/// <summary>
/// Event for notifying listeners that a property changed. Part of INotifyPropertyChanged
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public int MessageId { get; set; }
private DateTime timeStamp;
public DateTime TimeStamp
{
get
{
return timeStamp;
}
set
{
timeStamp = value;
OnNotifyPropertyChanged( "TimeStamp" );
}
}
You're saying that the DataTemplate to display a GeneralMcmMessage is to instantiate new GeneralMcmMessage.
<DataTemplate DataType="local:GeneralMcmMessage">
<local:GeneralMcmMessage />
</DataTemplate>
I'd recommend instead of making a collection of your UserControl to make a collection of your model object instead, and bind to the properties within that within your UserControl.
Either way though - the object you created in code will be the DataContext for the one you created in XAML so removing the ElementName=_this should bind appropriately. Try this simplified XAML in your UserControl instead.
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="0">
<TextBlock Name="MessageDateTime" Text="{Binding TimeStamp, StringFormat=MM/dd/yyyy h:mm:ss.fff tt \'GMT\' (zzz)}" />
<TextBlock Name="MessageTypeLabel" Margin="15,0,5,0" Text="Type:"/>
<TextBlock Name="MessageType" Text="{Binding Type}" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="1">
<TextBlock Name="MessageNameLabel" Margin="0,0,5,0" Text="Message Name:" />
<TextBlock Name="MessageNameValue" Text="{Binding MessageName}" TextWrapping="Wrap" />
</StackPanel>
<StackPanel VerticalAlignment="Stretch" Orientation="Vertical" Grid.Row="2">
<TextBlock Name="MessageLabel" Text="Message:"/>
<TextBlock Name="Message" Margin="10,0,0,0" Text="{Binding MessageContent}" />
</StackPanel>
You don’t post all code of GeneralMcmMessage hence I don’t know if you set DataContext in user control for example in constructor of GeneralMcmMessage.
I tried replicate your problem.
User control GeneralMcmMessage code behind
public partial class GeneralMcmMessage : UserControl, INotifyPropertyChanged
{
private int _messageId;
public int MessageId
{
get
{
return _messageId;
}
set
{
_messageId = value;
OnPropertyChanged("MessageId");
}
}
private DateTime _timeStamp;
public DateTime TimeStamp
{
get
{
return _timeStamp;
}
set
{
_timeStamp = value;
OnPropertyChanged("TimeStamp");
}
}
public GeneralMcmMessage()
{
InitializeComponent();
//don’t set data context here
//DataContext = this;
}
}
User control GeneralMcmMessage XAML
<StackPanel>
<TextBlock Margin="5" FontSize="20" Text="{Binding Path=MessageId}"/>
<TextBlock Margin="5" FontSize="20" Text="{Binding Path=TimeStamp}"/>
</StackPanel>
User control GeneralMcmMessage usage
public partial class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<GeneralMcmMessage> _generalMessages;
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public ObservableCollection<GeneralMcmMessage> GeneralMcmMessages
{
get { return _generalMessages; }
set
{
_generalMessages = value;
OnPropertyChanged("GeneralMcmMessages");
}
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
GeneralMcmMessages = new ObservableCollection<GeneralMcmMessage>();
for (int i = 0; i < 10; i++)
{
var newMsg = new GeneralMcmMessage
{
MessageId = i,
TimeStamp = DateTime.Now,
};
GeneralMcmMessages.Add(newMsg);
}
}
}
User control GeneralMcmMessage usage XAML
<ListBox x:Name="ListBox"
Margin="5"
ItemsSource="{Binding Path=GeneralMcmMessages}">
<ListBox.ItemTemplate>
<DataTemplate DataType="stackoverflow:GeneralMcmMessage">
<stackoverflow:GeneralMcmMessage/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If this not solve your problem could you please post all GeneralMcmMessage?
If you want I can upload sample project for you.
Thank you
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.
}
}
<ListBox Height="434" HorizontalAlignment="Left" Margin="6,238,0,0" Name="listBox1" VerticalAlignment="Top" Width="432" DataContext="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" Margin="4" Foreground="{StaticResource PhoneAccentBrush}"></TextBlock>
<StackPanel Orientation="Horizontal" Margin="4">
<TextBlock Text="Set" Margin="16" Foreground="{StaticResource PhoneAccentBrush}" />
<TextBlock Text="Weight" Margin="16" Foreground="{StaticResource PhoneAccentBrush}" />
<TextBlock Text="Reps" Margin="10,16,0,16" Foreground="{StaticResource PhoneAccentBrush}" />
</StackPanel>
<ListBox Name="setsAndReps" Height="auto" Width="auto" ItemsSource="{Binding Sets}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding SetNumber}"/>
<TextBox Text="{Binding Weight}"/>
<TextBox Text="{Binding Reps}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The outer listbox's item source is being set to an observable collection of a user defined class called excercise
public class excercise : IComparable, IEquatable<excercise>, INotifyPropertyChanged
{
string name;
int max;
int NUM_SETS;
ObservableCollection<set> sets;
public event PropertyChangedEventHandler PropertyChanged;
public string Name
{
get { return this.name; }
set { this.name = value; }
}
public excercise(string name)
{
this.name = name;
this.NUM_SETS = 0;
this.sets = new ObservableCollection<set>();
}
public ObservableCollection<set> Sets
{
get{return this.sets; }
}
public ObservableCollection<set> getSets()
{
return this.sets;
}
}
The properties in the inner list box are from the set class but none of them are being displayed and I am not sure what the problem is.
your first listbox doesn't have any itemsource set and the datacontext is set to an empty binding (both on line 1 of your code)