wpf Listview with textbox error - c#

I got a listview with a gridview cell template, as a textbox.
I can change the itemssource in the ui at runtime, but I can't do it, in code behind..
Please any ideas why would be a appreciated.
it's bound to a custom list.
this is my code so far:
Xaml template.
<Style TargetType="{x:Type TextBlock}" x:Key="GridBlockStyle">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Visibility" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Converter={StaticResource boolToVis}, ConverterParameter=False}" />
</Style>
<Style TargetType="{x:Type FrameworkElement}" x:Key="GridEditStyle">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Visibility" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Converter={StaticResource boolToVis}, ConverterParameter=True}" />
</Style>
<DataTemplate x:Key="txt_Field" DataType="{x:Type GridViewColumn}">
<Grid>
<TextBlock Text="{Binding Path=txt}" Style="{StaticResource GridBlockStyle}"/>
<TextBox Style="{StaticResource GridEditStyle}" Text="{Binding Path=txt}"/>
</Grid>
</DataTemplate>
Code behind:
DataTemplate t_txt = (DataTemplate)window.FindResource("txt_Field");
gridView.Columns.Add(new GridViewColumn { Header = "txt", CellTemplate = t_txt });
it updates the itemssource and as soon as the foreach loops are done the Entries are being overriden to null.
try
{
foreach (Items1 item in TempList)
{
foreach (Items1 item2 in list)
{
if (item.num == item2.num)
{
item2.txt = item.txt;
}
}
}
listview.Items.Refresh();
}
catch { }

I found a solution, but I still want to know why it happent..
this is the solution:
for (int i = 0; i < TempList.Count; i++)
{
if (Order_TempList[i].txt == ((Items1)listview.SelectedItem).txt)
{
((Items1)listview.SelectedItem).txt = Order_TempList[i].txt;
i = TempList.Count;
}
}
I can see the error very clearly now.
It's because there is two lists and the visual list (listview.Items) is being updated and not the physical list (TempList).

Related

ListBox HasItems DataTrigger not working when Items are cleared from ItemsSource

I have a Listbox and I have a DataTrigger in xaml to check if there are no items in the ListBox then Hide it (Please see the HasItems DataTrigger). At some point in my application I am Clearing the items from the ItemsSource i.e FilteredVolumesList (Please see the DeSelectAssays method) assuming the ListBox would be hidden because there are no Items In the ItemsSource.
But the problem is the DataTrigger dosen't seem to work and the ListBox is not being collapsed. Please help. I dont want to create a bool property for visibility and keep setting to false. Please note I am doing something like this in xaml ListBox CLear Items Xamly
Here is my xaml
<ListBox
Grid.Row="1"
x:Name="LstVolumes"
HorizontalAlignment="Center"
Margin="0,90,0,0"
VerticalAlignment="Top"
ItemsSource="{Binding FilteredVolumesList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
SelectionChanged="LstVolumes_SelectionChanged"
BorderThickness="0">
<ListBox.Style>
<Style
TargetType="{x:Type ListBox}"
BasedOn="{StaticResource ListBoxDarkBackgroundStyle}">
<Setter
Property="Template"
Value="{StaticResource ListBoxVolumesTemplate}"></Setter>
<Style.Triggers>
<DataTrigger
Binding="{Binding HasItems,RelativeSource={RelativeSource Self},UpdateSourceTrigger=PropertyChanged}"
Value="False">
<Setter
Property="Visibility"
Value="Collapsed"></Setter>
</DataTrigger>
<DataTrigger
Binding="{Binding DataContext.IsVolumeRepeaterVisible,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}}"
Value="False">
<Setter
Property="Template"
Value="{StaticResource ListBoxNoRepeaterTemplate}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Button
x:Name="VolumesButton"
Style="{StaticResource ButtonLightTextGradientDarkBackgroundStyle}"
Margin="{StaticResource AllControlsMargin}"
Click="VolumesButton_Click">
<Button.Content>
<StackPanel
x:Name="stkInnerChildPanel"
Orientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock
Style="{StaticResource TextBlockLightTextStyle}"
x:Name="TblVolume"
Text="{Binding volume_display_value,StringFormat={}{0} µg}"></TextBlock>
</StackPanel>
</Button.Content>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And I am clearing the items like this from the code behind
private ReadJsonAssayViewModel AssayViewModel = null;
public RunSetUpMainContentUserControl()
{
InitializeComponent();
AssayViewModel = ReadJsonAssayViewModel.ReadJsonAssayViewModelInstance;
this.DataContext = AssayViewModel;
FindAssociatedChildrenInstance = FindChildrenAndAssociatedControlsHelper.FindAssociateChildrenInstance;
Messenger.Default.Register<NotificationMessage>(this, DeSelectAssays);
}
private void DeSelectAssays(NotificationMessage obj)
{
for (int i = 0; i < LstAssays.Items.Count; i++)
{
ToggleButton btn = FindAssociatedChildrenInstance.AssociatedPanel(LstAssays, "AssaysButton", i, TargetType.ListAssays, typeof(ToggleButton)) as ToggleButton;
btn.IsChecked = false;
}
LstAssays.SelectedIndex = -1;
AssayViewModel.FilteredVolumesList.Clear();
AssayViewModel.IsStartRunEnabled = false;
this.Focus();
}
Here is the FilteredVolumesList in the viewmodel
private List<Volume> _filteredVolumesList;
public List<Volume> FilteredVolumesList
{
get
{
return _filteredVolumesList;
}
set
{
_filteredVolumesList = value;
OnPropertyChanged("FilteredVolumesList");
}
}

WPF lazy binding context menu items source

I successfully bind MenuModel to MenuItem.ItemsSource. However, the items should be contextualized. Right now, I populate the ViewModel collection and the data is ready to be bound to items source, but that's not covering all my scenarios.
I need to re-populate the ViewModel collection when the context menu is opening, that is, my goal is to only populate the collection at context menu opening, because earlier don't make sense (the items should be contextualized by ListBox SelectedItem).
XAML
<Style x:Key="ActionMenuItemStyle" TargetType="MenuItem" BasedOn="{StaticResource MetroMenuItem}">
<Setter Property="Visibility" Value="{Binding IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Setter Property="Icon" Value="{StaticResource ActionMenuItemIcon}" />
<Setter Property="IsCheckable" Value="{Binding IsCheckable, Mode=OneWay}" />
<Setter Property="IsChecked" Value="{Binding IsChecked, Mode=OneWay}" />
<Setter Property="Command" Value="{Binding Action}" />
<Setter Property="CommandParameter" Value="{Binding ActionParameter}" />
</Style>
<HierarchicalDataTemplate DataType="{x:Type model:MenuModel}" ItemsSource="{Binding Children}">
<MenuItem Header="{Binding Path=Header}" Style="{StaticResource ActionMenuItemStyle}"
UsesItemContainerTemplate="True" ItemContainerTemplateSelector="{StaticResource ActionMenuItemContainerTemplateSelector}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type model:SeparatorMenuModel}">
<Separator Style="{StaticResource {x:Static MenuItem.SeparatorStyleKey}}"/>
</DataTemplate>
<ContextMenu x:Key="OneItem">
<MenuItem Header="{x:Static resx:StudioResources.Advanced}">
<MenuItem Header="{x:Static resx:StudioResources.MoveToRoutineMenu}"
ItemsSource="{Binding PlacementTarget.Tag.Routines, RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}"
UsesItemContainerTemplate="True"
ItemContainerTemplateSelector="{StaticResource ActionMenuItemContainerTemplateSelector}"/>
</MenuItem>
</ContextMenu>
ViewModel
public IObservableCollection<IMenuModel> Routines { get; private set; }
protected override void OnViewLoaded(object view)
{
base.OnViewLoaded(view);
GetParent().Routines.CollectionChanged += (s, e) =>
{
Routines.Clear();
var names = GetParent().Routines.Where(r => r != GetParent().ActiveRoutine).Take(5).OrderBy(r => r);
var menus = names.Select(name => new MenuModel(name, new MenuAction<string>(MoveToRoutine), name)).ToList();
menus.ForEach(m => m.WithEditor(GetParent()));
Routines.AddRange(menus);
};
}
I listen to an event to re-populate the collection, but actually I need to listen to several other events, and I wonder if there is a clean way, like populate on context menu opening.

Dynamically Create TextBlock and TextBox in XAML WPF

My Question Is I have a grid where number of TextBlock and TextBox will vary as per the ComboBox SelectedItem Change
So, what I want is that I have written a function for get the details of the TextBlock and TextBox.
C# Function
public void GetAdditionalAttributes()
{
using (Entities _entities = new Entities())
{
var attributeAll = (from c in _entities.AdditionalAttributeValues
where c.DeviceID == 35
select new AttributesClass { AttributeValue = c.AdditionalAttributeValue1, AttributeName = c.AdditionalAttribute.Name }).ToList();
DeviceAttributes = new ObservableCollection<AttributesClass>(attributeAll);
}
}
Now In the XAML I was trying:
<Style x:Key="AdditionalAttributeDisplay"
TargetType="Grid"
x:Name="AdditionalAttributeDisplay"
>
<Style.Resources>
<Style TargetType="ItemsControl">
<Setter Property="ItemsSource"
Value="{Binding DeviceAttributes}" />
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedValue, ElementName=DeviceTypeComboBox}"
Value="1">
<Setter Property="ItemsSource"
Value="{Binding DeviceAttributes}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
But I don't know how to create a TextBlock or TextBox with ItemSource binding.
You can change the ItemTemplate of your ItemsControl.
<Style TargetType="ItemsControl">
<Setter Property="ItemTemplate">
<Setter.Value>
<ItemContainerTemplate>
<Grid>
<TextBox Width="100" Height="20" Text={Binding AttributeName}/>
</Grid>
</ItemContainerTemplate>
</Setter.Value>
</Setter>
</Style>
In above snippet replace PropertyName with DeviceAttributes member you want

WPF treeview does not show child nodes when not adding them in vm's constructor

I have a strange problem with a WPF treeview. In my viewmodel I am doing this:
private ObservableCollection<ITreeItem> _Tree = new ObservableCollection<ITreeItem>();
public ObservableCollection<ITreeItem> Tree
{
get { return this._Tree; }
}
Now when I add some dummy Parent / child data in the constructor of the viewmodel like this:
var parent = new ParentItem(1, "test", "test2");
this.Tree.Add(parent);
for (int i = 0; i < 10; i++)
{
parent.Childs.Add(new Child { Name= "test", Description= "test2" });
}
parent.IsExpanded = true;
the tree is displaying correctly.
However, as soon as I am adding some child items via a method (with dispatcher) they do not show at all. When i call this method, for example, only the root node is showing.
public void Update()
{
DispatcherSingleton.Instance.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal,
new Action(delegate
{
var parent = new ParentItem(1, "test", "test2");
this.Tree.Add(parent);
for (int i = 0; i < 10; i++)
{
parent.Childs.Add(new Child { Name= "test", Description= "test2" });
}
parent.IsExpanded = true;
})
);
}
Here is the XAML for the treeview
<ResourceDictionary>
<Style TargetType="TreeViewItem" x:Key="itmContStyle">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
<HierarchicalDataTemplate x:Key="hDataTemplate" ItemsSource="{Binding Childs}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image, Mode=TwoWay}" Margin="1" />
<Image x:Name="currentImage" Source="/WpfApp;component/Resources/Images/ac.png" Visibility="Collapsed"></Image>
<TextBlock Text="{Binding SortOrder}" Margin="1" />
<TextBlock Text="." Margin="0,1,1,0" />
<TextBlock Text="{Binding Bezeichnung}" Margin="1" />
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=IsSelected}" Value="True">
<Setter TargetName="currentImage" Property="Visibility" Value="Visible"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
</ResourceDictionary>
...
<TreeView HorizontalAlignment="Stretch" VerticalAlignment="Top"
BorderThickness="0"
ItemsSource="{Binding Tree}"
ItemContainerStyle="{StaticResource itmContStyle}" ItemTemplate="{StaticResource hDataTemplate}">
</TreeView>
It appears that you have got your naming mixed up. In your code, you show this line:
parent.Childs.Add(new Child { Name= "test", Description= "test2" });
This makes me think that your data type has a Childs property. But then in your XAML, you have this:
<HierarchicalDataTemplate x:Key="hDataTemplate" ItemsSource="{Binding ChildSteps}">
...
</HierarchicalDataTemplate>
I'm guessing that one of these is wrong. So, try this XAML instead:
<HierarchicalDataTemplate x:Key="hDataTemplate" ItemsSource="{Binding Childs}">
...
</HierarchicalDataTemplate>

Cannot change the style of the selected item in a ListBox

I´m trying to change the focused/selected item of a ListBox. My application is based on this article.
At the moment I´m trying to set the ListBoxItem style via data templates:
<DataTemplate x:Key="ItemTemplate">
<TextBlock Text="{Binding}"
Foreground="Black"
FontFamily="Segoe UI"
FontSize="22"
HorizontalAlignment="Left"
Padding="15,10,0,0"
/>
</DataTemplate>
<DataTemplate x:Key="SelectedTemplate">
<TextBlock Text="{Binding}"
Foreground="Red"
FontFamily="Segoe UI"
FontSize="30"
HorizontalAlignment="Left"
Padding="15,10,0,0"
/>
</DataTemplate>
My idea was to switch between those templates using a trigger:
<Style TargetType="{x:Type ListBoxItem}" x:Key="ContainerStyle">
<Setter Property="ContentTemplate" Value="{StaticResource ItemTemplate}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource SelectedTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
The ListBox looks like this:
<ListBox x:Name="valuesItemsCtrl"
BorderThickness="0"
ItemContainerStyle="{StaticResource ContainerStyle}"
Background="Transparent"
Tag="{Binding }">
<ListBox.AlternationCount>
<Binding>
<Binding.Path>Values.Count</Binding.Path>
</Binding>
</ListBox.AlternationCount>
<ListBox.ItemsSource>
<Binding>
<Binding.Path>Values</Binding.Path>
</Binding>
</ListBox.ItemsSource>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
At the end I add the template to another ListBox:
<ListBox x:Name="tumblersCtrl"
BorderThickness="0"
Background="Transparent"
ItemsSource="{Binding Tumblers, ElementName=thisCtrl}"
ItemTemplate="{StaticResource TumblerTemplate}">
</ListBox>
Thanks for any help or hint!
Use ItemTemplate and data triggers:
<ListBox ItemsSource="{Binding}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"
Foreground="Black"
FontFamily="Segoe UI"
FontSize="22"
HorizontalAlignment="Left"
Padding="15,10,0,0"
x:Name="tbName"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter TargetName="tbName" Property="Foreground" Value="Red"/>
<Setter TargetName="tbName" Property="FontSize" Value="30"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
where bound data is a collection of:
public class ViewModel : ViewModelBase
{
public String Name
{
get { return name; }
set
{
if (name != value)
{
name = value;
OnPropertyChanged("Name");
}
}
}
private String name;
public Boolean IsSelected
{
get { return isSelected; }
set
{
if (isSelected != value)
{
isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
private Boolean isSelected;
}
Window code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new[]
{
new ViewModel { Name = "John", IsSelected = true },
new ViewModel { Name = "Mary" },
new ViewModel { Name = "Pater" },
new ViewModel { Name = "Jane" },
new ViewModel { Name = "James" },
};
}
}
If you want to change the templates use DataTemplateSelector.
Dismiss your ContainerStyle and instead set the ListBox.ItemsTemplateSelector to your custom datatemplateselector as static resource.
You can find a detailed example in this link.
EDIT :
According to your comment you don't need DataTemplate just set these two properties in the Trigger:
<Style TargetType="{x:Type ListBoxItem}" x:Key="ContainerStyle">
<Setter Property="Foreground" Value="Black" />
<Setter Property="FontSize" Value="22" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Padding" Value="15,10,0,0" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontSize" Value="30" />
</Trigger>
</Style.Triggers>
</Style>

Categories