Images disappear from the ListView in WPF after an action - wpf

Images load correctly to the listview, but whenever I click on the listview and change the SelectedItem, the images dissapear. I can see the elements and do everything with them, but they are a simple row and the image itself is not in the row.
This is the XAML for the ListView
<ListView Name="testLB" ItemsSource="{Binding Images}" SelectedItem="{Binding SelectedImage}" HorizontalAlignment="Left" Height="393" Margin="627,28,0,0" VerticalAlignment="Top" Width="244" SelectionChanged="testLB_SelectionChanged"/>
And this is part of my ViewModel.
public ObservableCollection<Image> Images { get; private set; }
public Image SelectedImage { get => selectedImage;
set {
this.selectedImage = value;
this.OnPropertyChanged("SelectedImage");
} }
private Image selectedImage;

Image is a subclass of UIElement, and should hence not be used as item type in a view model.
Use ImageSource instead (and add e.g. BitmapImages or BitmapFrames to your collection):
public ObservableCollection<ImageSource> Images { get; private set; }
public ImageSource SelectedImage { ... }
Then make your ListView's ItemTemplate contain an Image element:
<ListView ItemsSource="{Binding Images}" SelectedItem="{Binding SelectedImage}" ...>
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Related

How to binding TextBlock text in TabControl ItemTemplate?

In sidebar menu(RTL) when i clicked on which one, a TabItem added to tbMain. My problem is that how i can show sidebar clicked text in TabItem header in TextBlock using Binding?
here is Image , XAML and CodeBehind.
XAML:
<TabControl x:Name="tbMain" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="6" Grid.RowSpan="5" Margin="0">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" VerticalAlignment="Center" Foreground="#000000"/>
</DataTemplate>
</TabControl.ItemTemplate>
Code Behind :
public WinFinance() {
InitializeComponent();
var definitionsMenu = new List<MenuSubItems>();
definitionsMenu.Add(new MenuSubItems("area", new ucrArea()));
definitionsMenu.Add(new MenuSubItems("client", new ucrClient()));
definitionsMenu.Add(new MenuSubItems("cash" , new ucrCash()));
tbMain.Items.Add(new ucrMainControl());
}
First of all, I will assume that you somehow made that List<MenuSubItems> as ItemsSource of tbMain in the part of code that you didn't uploaded.
In this case, If you want to make some string property("area", "client", "cash"...) as a Header of TabItems, You can use Style like:
<TabControl x:Name="tbMain" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="6" Grid.RowSpan="5" Margin="0">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding MenuSubHeader}"/>
</Style>
</TabControl.ItemContainerStyle>
.......
Then it will works.
Edit: This was my code-behind and MenuSubItems class I wrote. I don't have any knowledge about your project so I just wrote just to show how it works.
public MainWindow()
{
InitializeComponent();
var definitionsMenu = new List<MenuSubItems>();
definitionsMenu.Add(new MenuSubItems("area", new object()));
definitionsMenu.Add(new MenuSubItems("client", new object()));
definitionsMenu.Add(new MenuSubItems("cash", new object()));
tbMain.ItemsSource = definitionsMenu;
}
public class MenuSubItems
{
public string MenuSubHeader { get; set; }
public object Content { get; set; }
public MenuSubItems(string key, object value)
{
MenuSubHeader = key;
Content = value;
}
}
For it to be achieved the way you're XAML is wrote, you must have Items that has a property named Text (also, if you want it to update itself dynamically, implement INotifyProperty).
The best way to do that is by creating a ViewModel with the data you need and bind you're sidebar values with the same property that you bind the tabs.

Setting DataGrid and ContextMenu with Same DataContext

I am trying to dynamically create a Context Menu for a data grid that passes in the selected menu item (Mvvm). I want the DataContext to be the same for the for the context menu as the grid.
I have the following Xaml
<Grid>
<!-- Cut some other stuff -->
<Border Grid.Row="2" BorderBrush="Black" BorderThickness="1">
<DataGrid x:Name="MyDataGrid" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Path=GridData}" AutoGenerateColumns="False" IsReadOnly="True" GridLinesVisibility="None" SelectionUnit="Cell" SelectionMode="Single">
<DataGrid.ContextMenu>
<ContextMenu ItemsSource="{Binding ContextMenuActions}">
<MenuItem Header="{Binding DisplayName}" Command="{Binding Command}" />
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns>
<DataGridTextColumn Header="DataOne" Width="130" Binding="{Binding Path=DataOne}"/>
<DataGridTextColumn Header="DataTwo" Width="100" Binding="{Binding Path=DataTwo}"/>
<DataGrid.Columns>
<DataGrid.InputBindings>
<MouseBinding Gesture="RightClick" Command="{Binding DataGridRightClick}" CommandParameter="{Binding ElementName=MyDataGrid, Path=SelectedCells}" />
</DataGrid.InputBindings>
</DataGrid>
</Border>
</Grid>
and the following classes for my data context that I use for my datagrid and would also like to use for my context menu (I have cut out all the data grid population code for readability ) and menuitems
public class DataViewModel : ViewModelBase // Implements INotifyPropertyChanged
{
// All code that populates the grid has been removed
public ObservableCollection<MenuItemViewModel> ContextMenuActions { get; set; }
public ICommand DataGridRightClick { get; private set; }
public MarketDataViewModel()
{
DataGridRightClick = new RelayCommand(RightClick);
}
public void RightClick(object obj)
{
MenuItemViewModel menuItem = new MenuItemViewModel("Test", new RelayCommand(TestCall));
ContextMenuActions.Add(menuItem); // I ensure this is added on the gui thread
MenuItemViewModel menuItem1 = new MenuItemViewModel("Test2", new RelayCommand(TestCall));
ContextMenuActions.Add(menuItem1); // I ensure this is added on the gui thread but for
}
private void TestCall(object obj)
{
// want to pass in the selected menuitem
}
}
public class MenuItemViewModel
{
public MenuItemViewModel(string displayName,ICommand command)
{
DisplayName = displayName;
Command = command;
}
public string DisplayName { get; set; }
public ICommand Command { get; set; }
}
Currently when I click on the datagrid the right click event gets called and runs fine but an empty context menu appears on the grid.
Thanks,
Nick
You need to bind to the DataContext.ContextMenuActions of the parent DataGrid. The easiest way to achieve this is by using the following binding:
<ContextMenu ItemsSource="{Binding DataContext.ContextMenuActions, ElementName=MyDataGrid}" ...

How do I bind to something outside a datacontext

I have a listbox in WPF that is in the Layout Root.
I also have a Frame that is in the Layout Root as well.
The listbox is composed of items that have a string(Name) and a framework element(UI).
How do I bind the frame's content to be the UI property of the listbox's selected item property?
If you need a codebehind, how would you do this in MVVM
I used a ContentControl instead of Frame since I had problem binding to Content property, I never got it to refresh after binding changed. I didn't do proper MVVM, Data should not be hosted inside the view.
XAML:
<Window.Resources>
<CollectionViewSource x:Key="CVS" Source="{Binding}" />
</Window.Resources>
<StackPanel DataContext="{Binding Source={StaticResource CVS}}">
<ListBox
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
DisplayMemberPath="Name">
</ListBox>
<ContentControl Content="{Binding Path=UI}" />
</StackPanel>
Code behind:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace BindDemo
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Data = new List<DataItem>();
Data.Add(new DataItem("TextBox", new TextBox(){ Text="hello" }));
Data.Add(new DataItem("ComboBox", new ComboBox()));
Data.Add(new DataItem("Slider", new Slider()));
DataContext = Data;
}
public List<DataItem> Data
{
get; private set;
}
}
public class DataItem
{
public DataItem(string name, FrameworkElement ui)
{
Name = name;
UI = ui;
}
public string Name { get; private set; }
public FrameworkElement UI { get; private set; }
}
}
It sounds as you want to display list of objects and details for selected object. If I am right, solution in MVVM may be following:
<ListView ItemsSource="{Binding ObjectsList}" IsSynchronizedWithCurrentItem="True" />
<ContentControl Content="{Binding ObjectsList}">
<ContentControl.ContentTemplate>
<DataTemplate>
<!-- details template -->
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>

WPF ListView show Image

I have a simple class that contains a string and an WPF Image control:
public class User
{
public string Name { get; set; }
public System.Windows.Controls.Image Image { get; set; }
}
Now I'm binding a list of instances of this class to a ListView.
What I would like to do now is make ListView display the Image property.
I've tried settings DisplayMemberPath to Image, but this shows the ToString value of Image instead (System.Windows.Controls.Image).
How can I make it actually show the control?
Here's the XAML code:
<ListView Name="listView1" DisplayMemberPath="Image" />
Thanks!
You could create a DataTemplate that uses a ContentPresenter to display the image:
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Image}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

How to set Itemsource to a Comobox Inside a DataTemplate Dynamically?

I have one Listbox and applied one DataTemplate like this
<ListBox>
<ListBox.ItemTemplate>
<Grid>
<TextBlock Text="{Binding Path=Name}" Grid.Row=0/>
<ComoboBox Name="test"
DisplayMemberPath="Country"
SelectedValuePath="Country_ID">
</Grid>
How will I load ItemSource to this ComboBox dynamically based on each item selected in the ListBox? Iam new to WPF... pls help with your valuable suggestions.
<ListBox>
<ListBox.ItemTemplate>
<Grid>
<TextBlock Text="{Binding Path=Name}" Grid.Row=0/>
<ComoboBox Name="test"
DataContent="{Binding RelativeSource={RelativeSource AncestorType=ListBox}}"
ItemsSource="{Binding}"
DisplayMemberPath="Country"
SelectedValuePath="Country_ID">
</Grid>
Now your combocbox is always have the same itemssource as the parent listbox.
One way to do this is to bind the ItemsSource of your ComboBox to the SelectedValue property of the ListBox. For this to work the ListBox needs to be bound to a collection of items that contains a list of items that the ComboBox will bind to.
<ListBox
x:Name="CategoryList"
ItemsSource="{Binding Path=MasterList,
RelativeSource={RelativeSource AncestorType=Window}}"
DisplayMemberPath="MasterProperty"
SelectedValuePath="Details"
/>
<ComboBox
ItemsSource="{Binding Path=SelectedValue, ElementName=CategoryList}"
DisplayMemberPath="DetailProperty"
Grid.Row="1"
/>
In this example I have created a public property in the code behind of the window that exposes a list of objects containing the Details collection.
public List<Master> MasterList { get; set; }
public class Master
{
public string MasterProperty { get; set; }
public List<Detail> Details { get; set; }
}
public class Detail
{
public string DetailProperty { get; set; }
}

Resources