ListBox.SelectedItem selected wrong row - c#

I create ListBox, wich rows can be editable:
<ListBox Grid.Row="1" x:Name="lbKeys" BorderBrush="Gray"
ItemsSource="{Binding Path=Templates}"
IsSynchronizedWithCurrentItem="True"
Focusable="True"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch"
ItemContainerStyle="{StaticResource ResourceKey=lbStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="LightGray" Background="WhiteSmoke"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Name="grEditRow">
<TextBox x:Name="tblbRow" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" Margin="2"
Background="Transparent"
HorizontalAlignment="Stretch"
/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But, when i select row for edit (and i can do it)- i want to delete this row by clicking to button:
<Button x:Name="btDelTemplate" Click="btDelTemplate_Click" Height="22" Width="22"
ToolTipService.ShowOnDisabled="True"
ToolTip="{lang:Link LocalePath=RemoveTemplate,DesignValue='Remove row'}"
>
</Button>
And event handler of it:
if(lbKeys.SelectedItem!=null)
RemoveItem(lbKeys.SelectedItem as Row);
But, selected item often is wrong! As i understand- if i select item by clicking at left border of row- it works well, but when click at textbox inside row- selected item is wrong.
How to fix it?
Thank you!

I find a workaround.
Here the code:
XAML:
<ListBox Grid.Row="1" x:Name="lbKeys" BorderBrush="Gray"
ItemsSource="{Binding Templates}"
IsSynchronizedWithCurrentItem="True"
Focusable="True"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch"
ItemContainerStyle="{StaticResource ResourceKey=lbStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="LightGray" Background="WhiteSmoke"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBox x:Name="tblbRow" Text="{Binding Text,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Tag="{Binding}"
GotFocus="tblbRow_GotFocus"
TextWrapping="Wrap" Margin="2"
Background="Transparent"
HorizontalAlignment="Stretch"
/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Key lines:
Tag="{Binding}"
GotFocus="tblbRow_GotFocus"
C# handlers:
private void tblbRow_GotFocus(object sender, RoutedEventArgs e)
{
var textBox = sender as TextBox;
lbKeys.SelectedItem = textBox.Tag;
}
private void btDelTemplate_Click(object sender, RoutedEventArgs e)
{
try
{
foreach (var item in lbKeys.Cast<Row>())
{
if (item.Template.Id == (lbKeys.SelectedItem as Row).Template.Id)
{
_viewModel.RemoveTemplate(item);
break;
}
}
DataContext = _viewModel;
}
catch(Exception ex)
{
throw;
}
}

You can write a handler for GotFocus of the TextBox and change SelectedItem in that programmatically.
--------- Update ----------
private void tblbRow_GotFocus(object sender, RoutedEventArgs e)
{
lbKeys.SelectedItem = (sender as TextBox).DataContext as Row;
}
and you should write some code for Row class to let its objects be comparable:
public class Row
{
public Row() { }
private string _text;
public String Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
public override int GetHashCode()
{
return _text;
}
public bool Equals(Row r)
{
return r._text == _text;
}
public override bool Equals(object r)
{
Row row = r as Row;
return row != null && row._text == _text;
}
}

Related

How to Create a Filter in WPF using Datagrid and ComboBox

So here I have a MVVM form. the Form contains a Datagrid which is connected to the Databank. I also have a ComboBox which I want to use as a filter option. The Filter option shoud filter by the "AnlV nr" so when the user selects "01" from the ComboBox the datagrid should refresh and show only that "AnlV nr" that have "01" Below I will share you the code and you can see that i've gotten as far as showing the "AnlV" values in the ComboBox but I now do not know how to do the rest and make the filter work. Below is my Viewmodel and the Xaml code.
If anyone can help me with this I would really apreciate it.
Xaml Code:
<Window x:Class="QBondsFrontend.Views.Input.AnlVTexteView"
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:QBondsFrontend.Views.Input" xmlns:input="clr-namespace:QBondsFrontend.ViewModels.Input" d:DataContext="{d:DesignInstance Type=input:AnlVTexteViewModel}"
mc:Ignorable="d"
Title="AnlVTexteView"
Width="800"
MinHeight="400"
Height="490"
MinWidth="1010"
MaxWidth="1010"
UseLayoutRounding="True">
<Grid Background="#A8A8A8" >
<StackPanel VerticalAlignment="Top" Background="#A8A8A8" Orientation="Horizontal" Height="57">
<Label
Content="AnlV Nr.:" Height="35" FontSize="12"/>
<ComboBox Background="LightGray" Height="20" Width="70" ItemsSource="{Binding lstAnlVTexte}" SelectedItem="{Binding Search}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding AnlVPara}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Height="18" Width="68" Margin="5, 0"
Content="Filter löschen" FontSize="11" Style="{StaticResource STL_ButtonStandard}"
x:Name="filterlöschen"
Command="{Binding icdFilterDelete}"/>
</StackPanel>
<StackPanel Background="LightGray" VerticalAlignment="Top" Height="177" Margin="0,57,0,0">
<DataGrid x:Name="datagridXAML"
Height="177"
ItemsSource="{Binding lstAnlVTexte, Mode=TwoWay}"
Style="{StaticResource STL_DataGridReporting}"
CellStyle="{StaticResource STL_DataGridCellReporting}"
ColumnHeaderStyle="{StaticResource STL_DataGridColumnHeaderReporting}"
AlternatingRowBackground="#A8A8A8"
CanUserResizeColumns="False"
>
<DataGrid.Columns>
<DataGridTextColumn Header="AnlV-Nr"
Binding="{Binding AnlVPara}"
Width="60"/>
<DataGridTextColumn Header="gültig ab"
Binding="{Binding TextGueltigAb}"
Width="68"/>
<DataGridTextColumn Header="Text"
Binding="{Binding ParaText}"
Width="750"/>
<DataGridTextColumn Header="Info"
Binding="{Binding Info}"
Width="*"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
<StackPanel Background="#A8A8A8" HorizontalAlignment="Center" Margin="10,268,0,141" Width="1010" >
<Label Content="Bearbeitungsbereich" FontWeight="Bold" FontSize="12" Height="33" />
</StackPanel>
<StackPanel>
<StackPanel Orientation="Horizontal" Background="#A8A8A8" HorizontalAlignment="Center"
Width="1010" Margin="0,294,0,0" Height="31">
<Label Height="25" Width="60" Margin="20, 0, 0, 0" Content="AnlV-Nr.:" />
<ComboBox IsEditable="True" Background="gray" Height="22" Width="69" ItemsSource="{Binding AnlVPara}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding lstAnlVTexte}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<CheckBox Height="15" Margin="10, 0, 0, 0" />
<Label Height="26" Width="122" Content="Editierwarnungen" />
<StackPanel Height="48" Width="100"/>
</StackPanel>
<StackPanel Height="22" Orientation="Horizontal">
<Label Margin="20, 0, 0, 0" Content="gültig ab:" Height="27" />
<TextBox Background="LightGray" Height="20" Width="100" />
</StackPanel>
<StackPanel Height="50" Orientation="Horizontal">
<Label Content="Text:" Height="27" Width="38" Margin="42,0,0,10" />
<TextBox Background="LightGray" Width="500" Height="43" />
</StackPanel>
<StackPanel Orientation="Horizontal" >
<Label Content="Info:" Height="27" Width="38" Margin="42,0,0,0" />
<TextBox Background="LightGray" Width="500" Height="20" />
<Button x:Name="BTN_speichern" Width="80" Height="18" Margin="20,0,0,0" Content="Speichern"
Style="{StaticResource STL_ButtonStandard}" Command="{Binding icdSpeichern}"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
ViewModel:
using Newtonsoft.Json;
using QBondsData.DBModels;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Linq;
namespace QBondsFrontend.ViewModels.Input
{
public class AnlVTexteViewModel : BaseViewModel
{
#region data
private string _AnlVPara;
private DateTime _TextGueltigAb;
private string _ParaText;
private string _Info;
private List<AnlVhistText> _lstAnlVTexte;
private string _search;
#endregion
#region constructor
public AnlVTexteViewModel()
{
icdFilterDelete = new RelayCommand<object>(parameter => filterdelete(), parameter => true);
icdSpeichern = new RelayCommand<object>(parameter => speichern(), parameter => true);
GetData();
}
#endregion
#region members
public ICommand icdFilterDelete { get; set; }
public ICommand icdSpeichern { get; set; }
private string Search
{
get { return _search; }
set
{
_search = value;
OnPropertyChanged("Search");
}
}
public string AnlVPara
{
get
{
return _AnlVPara;
}
set
{
_AnlVPara = value;
OnPropertyChanged("AnlVPara");
}
}
public DateTime TextGueltigAb
{
get
{
return _TextGueltigAb;
}
set
{
_TextGueltigAb = value;
OnPropertyChanged("TextGueltigAb");
}
}
public string ParaText
{
get
{
return _ParaText;
}
set
{
_ParaText = value;
OnPropertyChanged("ParaText");
}
}
public string Info
{
get
{
return _Info;
}
set
{
_Info = value;
OnPropertyChanged("Info");
}
}
public List<AnlVhistText> lstAnlVTexte
{
get { return _lstAnlVTexte; }
set
{
_lstAnlVTexte = value;
OnPropertyChanged("lstAnlVTexte");
}
}
#endregion
#region methods
private void filterdelete()
{
}
private void speichern()
{
}
private async Task GetData()
{
HttpResponseMessage Response = await Globals.SendRequest("AnlVTexte/GetAnlVTexte"
, "GET");
if (Response.IsSuccessStatusCode)
{
lstAnlVTexte = JsonConvert.DeserializeObject<List<AnlVhistText>>
(await Response.Content.ReadAsStringAsync());
}
else
{
lstAnlVTexte = new List<AnlVhistText>();
Application.Current.Dispatcher.Invoke((Action)delegate
{
Globals.CloseReportByHash(this.GetHashCode()
, "Fehler! (HTTP Status " + Response.StatusCode + ")." +
"Kontaktieren Sie den Support.");
});
}
}
#endregion
}
}
When you change the type of lstAnlVTexte to ICollectionView you get two events CurrentChanged and CurrentChanging which you can handle in your viewmodel. From the ICollectionView you can get the CurrentItem.
Like this:
private List<AnlVhistText> _anlVTexte = new List<AnlVhistText>();
public AnlVTexteViewModel()
{
[...]
lstAnlVTexte = new CollectionView(_anlVTexte);
lstAnlVTexte.CurrentChanged += SelectionChanged; // raised after the current item has been changed.
lstAnlVTexte.CurrentChanging += SelectionChanging; // raise before changing the current item. Event handler can cancel this event.
}
private void SelectionChanged(object sender, EventArgs e)
{
var selectedItem = lstAnlVTexte.CurrentItem;
}
private void SelectionChanging(object sender, CurrentChangingEventArgs e)
{
}
private ICollectionView _lstAnlVTexte;
public ICollectionView lstAnlVTexte
{
get { return _lstAnlVTexte; }
set
{
_lstAnlVTexte = value;
OnPropertyChanged("lstAnlVTexte");
}
}
Here's a sample using the community toolkit mvvm and linq.
If you're not familiar, the toolkit does code generation.
This is a simple scenario to illustrate the approach.
Mainwindowviewmodel.
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private int selectedFilterInt = -1;
partial void OnSelectedFilterIntChanged(int newValue)
{
FilteredList = new ObservableCollection<MyItem>(FullList.Where(x=>x.Category == selectedFilterInt).ToList());
}
public List<int> FilterOptions { get; set; } = new List<int> {1,2,3};
private List<MyItem> FullList= new List<MyItem>
{
new MyItem{ Category = 1},
new MyItem{ Category = 1},
new MyItem { Category = 1 },
new MyItem { Category = 2 },
new MyItem { Category = 2 },
new MyItem { Category = 3 }
};
[ObservableProperty]
private ObservableCollection<MyItem> filteredList = new ObservableCollection<MyItem>();
public MainWindowViewModel()
{
FilteredList = new ObservableCollection<MyItem>(FullList);
}
}
There's a full list of all the items.
But a filtered list is going to be bound to the itemssource of my listbox ( equivalent to your datagrid ).
Due to the code generated, when selectedFilterInt changes, OnSelectedFilterIntChanged will be called. It's got a handler listening for property changed of SelectedFilterInt if you dug into the generated code.
That method uses a linq where to filter the full list into filtered list.
Setting that filtered list property raises property changed and the view re reads the new collection.
MainWindow. ( I did mention this is simplified )
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<StackPanel>
<ComboBox SelectedItem="{Binding SelectedFilterInt}"
ItemsSource="{Binding FilterOptions}"/>
<ListBox ItemsSource="{Binding FilteredList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Category}"/>
<TextBlock Text="{Binding Comment}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
</Window>
and MyItem
public partial class MyItem : ObservableObject
{
[ObservableProperty]
private int category = 0;
[ObservableProperty]
private string comment = "Some test string";
}
Which is a bit underwhelming visually but works:
In your code you need to get all the data into a collection.
Call that FulList.
You then need another collection which will be the filtered data.
Call this FilteredList.
Bind itemssource to FilteredList
Initially, you presumably want FilteredList to be = FullList
Then when the user selects something in the combobox you need to react to that.
You could bind selecteditem to a property and act in the setter or handle propertychanged like my code does.
However you do it, you get a new integer.
You then use that to filter FullList into a new collection which will replace the bound FilteredList.
You also need to somehow have one entry per AnlV nr whatever that is in your combobox.
AnlV nr isn't going to work as a property name since it's got a space but it is the equivalent to Category in my sample.
You will use that selected value in the linq.
Substitute the name of that property for Category. Substitute the type of whatever your collection is. Maybe that's AnlVhistText. I'm not sure.

Drag and Drop between listbox

I want to Drag and Drop Item between Listbox. One is located in MainWindow and one in UserControl. Tab control items are dynamically coded.([VideoListing], [AddTab, AddItem]) I'm curious if this works and then give me directions.
This is what I wanted.
enter image description here
And, this is my Codes
Mainwindow.xaml
<TabControl x:Name="scenarioCB" ItemsSource="{Binding}" Grid.Row="1" HorizontalAlignment="Stretch" Margin="5,0,5,5" VerticalAlignment="Stretch" SelectionChanged="ScenarioCB_SelectionChanged">
<TabControl.ItemTemplate>
<DataTemplate DataType="local:AddTab">
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="local:AddTab">
<ListBox x:Name="listBox" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" ItemsSource="{Binding Data}" AllowDrop="True" Drop="ListBox_Drop" DragEnter="ListBox_DragEnter" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<MediaElement Margin="3" Source="{Binding Path}" Height="64" Stretch="Uniform" IsMuted="True"/>
<TextBlock Margin="3" Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
Mainwindow.xaml.cs
var tabs = new ObservableCollection<AddTab>();
for (int i = 0; i < DateListCount; i++)
{
var tab = new AddTab();
tab = new AddTab() { Header = DateList[i] + " - " + TimeList[i] };
tab.Data.Add(new AddData() { TIME = TimeList[i] });
Console.WriteLine("i = {0}, Header = {1}, Time = {2}", i, DateList[i], TimeList[i]);
tabs.Add(tab);
}
DataContext = tabs;
AddTab.cs
class AddTab
{
public string Header { get; set; }
public string Time { get; set; }
public ObservableCollection<AddData> Data { get; } = new ObservableCollection<AddData>();
}
AddData.cs
class AddData
{
public string NAME { get; set; }
public string PATH { get; set; }
}
VideoPanel.xaml
<ListBox Grid.Row="0" x:Name="listBox" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" AllowDrop="True" Drop="ListBox_Drop" DragEnter="ListBox_DragEnter" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<MediaElement Margin="3" Source="{Binding Path}" Height="64" Stretch="Uniform" IsMuted="True"/>
<TextBlock Margin="3" Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
VideoPanel.xaml.cs
list.Add(new VideoListing()
{
Name = file_name,
Path = file,
});
VideoListing.cs
class VideoListing
{
public string Name { get; set; }
public string Path { get; set; }
}
If you have an example, please post the link.
Drag and Drop between listbox(MainWindow - UserControl)
Tabitems are dynamic coded
I solved this problem. Using by DragDrop.DoDragDrop
When I ran DragDrop.DoDragDrop(DependencyObject dragSourse, object data, DragDropEffects allowedEffects) when I pressed the left mouse button. And when I drop an item into another listbox, generate ListBox_Drop event. In LisetBox_Drop event, Just pull the data out of DragEventArgs.
Listbox - drag
private void ListBox_MouseMove(object sender, MouseEventArgs e)
{
DataObject dataObj = new DataObject();
dynamic Booth = listBox.SelectedItem as dynamic;
if (sender is ListBox && e.LeftButton == MouseButtonState.Pressed)
{
dataObj.SetData("Name", Booth.Name);
dataObj.SetData("Path", Booth.Path);
DragDrop.DoDragDrop(listBox, dataObj, DragDropEffects.Move);
}
}
Listbox - drop
private void ListBox_Drop(object sender, DragEventArgs e)
{
string name = (string)e.Data.GetData("Name");
string path = (string)e.Data.GetData("Path");
}

WPF ObservableCollection not updating view

this is xaml part
<ItemsControl x:Name="EventsTop">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,1,0,0">
<Button Content="{Binding Name}" Template="{DynamicResource ButtonFirst}" Height="50" Margin="15,0,0,0" Padding="10,0,15,0" FontSize="19" FontFamily="/Resources/Fonts/Font Awesome/#FontAwesome" BorderThickness="5,0,0,0" BorderBrush="#8CC152" Background="#2980B9" HorizontalContentAlignment="Left" Foreground="Black" Click="TabOpen" Tag="{Binding Id}"></Button>
<StackPanel Background="#2980B9" Margin="15,0,0,5" Visibility="Collapsed" AllowDrop="True" Tag="{Binding Id}" Drop="RowDrop">
<Border BorderThickness="5,0,0,0" BorderBrush="#8CC152">
<StackPanel>
<DockPanel LastChildFill="False">
<Label DockPanel.Dock="Left" Width="140" Content="Date" FontSize="19" BorderThickness="0,0,0,1" FontFamily="/Resources/Fonts/Open Sans/#Open Sans" BorderBrush="Black" HorizontalContentAlignment="Center"></Label>
<Label DockPanel.Dock="Left" Width="190" Content="Event" FontSize="19" BorderThickness="0,0,0,1" FontFamily="/Resources/Fonts/Open Sans/#Open Sans" BorderBrush="Black" HorizontalContentAlignment="Center"></Label>
<Label DockPanel.Dock="Left" Width="100" Content="Select" FontSize="19" BorderThickness="0,0,0,1" FontFamily="/Resources/Fonts/Open Sans/#Open Sans" BorderBrush="Black" HorizontalContentAlignment="Center"></Label>
</DockPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="150">
<ItemsControl ItemsSource="{Binding Details}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DockPanel LastChildFill="False">
<Label Content="{Binding Date}" DockPanel.Dock="Left" Width="140" FontSize="19" BorderThickness="0" FontFamily="/Resources/Fonts/Open Sans/#Open Sans" BorderBrush="Black" HorizontalContentAlignment="Center"></Label>
<Label Content="{Binding EventName}" DockPanel.Dock="Left" Width="165" FontSize="19" BorderThickness="0" FontFamily="/Resources/Fonts/Open Sans/#Open Sans" BorderBrush="Black" HorizontalContentAlignment="Center"></Label>
<Border Width="97">
<CheckBox VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding Checked}"></CheckBox>
</Border>
<Button Width="25" DockPanel.Dock="Left" Content="" BorderThickness="0" Background="Transparent" FontFamily="/Resources/Fonts/Font Awesome/#FontAwesome"></Button>
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</StackPanel>
</Border>
</StackPanel>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
this is xaml.cs
private void WindowLoaded(object sender, RoutedEventArgs e)
{
EventHelper eventHelper = new EventHelper();
TopEvents = eventHelper.GetSports(EventHelper.EventGroup.Top);
foreach (Sport item in TopEvents)
{
item.Name = "\uf196 " + item.Name;
}
EventsTop.ItemsSource = TopEvents;
AllEvents = eventHelper.GetSports(EventHelper.EventGroup.All);
foreach (Sport item in AllEvents)
{
item.Name = "\uf196 " + item.Name;
}
EventsAll.ItemsSource = AllEvents;
Sport.ItemsSource = eventHelper.GetSports(EventHelper.EventGroup.All);
}
private void RowMouseDown(object sender, MouseButtonEventArgs e)
{
DockPanel currentRow = (DockPanel) sender;
int rowOffset = Convert.ToInt32(currentRow.Tag);
DragDrop.DoDragDrop(currentRow,rowOffset,DragDropEffects.Copy);
}
private void RowDrop(object sender, DragEventArgs e)
{
int rowOffset = (int) e.Data.GetData(typeof (int));
AllEvents[0].Name = "1";
}
Also my model in collection
class Sport : INotifyPropertyChanged
{
private int _id;
private string _name = string.Empty;
private ObservableCollection<Details> _details = new ObservableCollection<Details>();
public int Id
{
get { return _id; }
set { _id = value; }
}
public string Name
{
get { return _name; }
set
{
_name = value;
NotifyPropertyChanged("Content");
}
}
public ObservableCollection<Details> Details
{
get { return _details; }
set { _details = value; }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
MessageBox.Show(info);
}
}
}
So when I am changing property its throwing MessageBox but not updating GUI.
I xaml.cs I am calling methods GetEvents thats
return ObservableCollection
I want to change Name in Sport which is in ObservableCollaction<Sport> AllEvents
You can see it in RowDrop method in xaml.cs
In debugging I notice that AllEvents[0].Name was changed but view was not updating
UPDATE
Part of ObservabelCollection declaration
public MainPage()
{
InitializeComponent();
AllEvents = new ObservableCollection<Sport>();
TopEvents = new ObservableCollection<Sport>();
EventsTop.ItemsSource = TopEvents;
EventsAll.ItemsSource = AllEvents;
}
private ObservableCollection<Sport> AllEvents;
private ObservableCollection<Sport> TopEvents;
UPDATE SECOND
I caught that when I am using window activated event it is working
I found solution.
So, ObservableCollection is working very well but,It needs to be refreshed
for appearing in view and for it we need to use
CollectionViewSource.GetDefaultView(ObservableCollection).Refresh()
method for it
I think it will help someone
The problem with property named passed to NotifyPropertyChanged method. The name of parameter should be property name. Please change the Name property as
public string Name
{
get { return _name; }
set
{
_name = value;
NotifyPropertyChanged("Name");
}
}
Use CallerMemberNameAttribute to avoid having to get the name correct and allowing refactoring:
private void NotifyPropertyChanged([CallerMemberName] string info = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
MessageBox.Show(info);
}
}
public string Name
{
get { return _name; }
set
{
_name = value;
NotifyPropertyChanged(); //now no need to specify
}
}
Every property setter should notify property change, so:
public IEnumerable<Details> Details //note IEnumerable, no calling code needs to know its concrete type
{
get { return _details; }
set
{
_details = value;
NotifyPropertyChanged();
}
}
And with an observable range collection you could do this:
private readonly ObservableRangeCollection<Details> _details = new ObservableRangeCollection<Details>();
public IEnumerable<Details> Details
{
get { return _details; }
set { _details.Replace(value); }
}
From MSDN.
Occurs when an item is added, removed, changed, moved, or the entire
list is refreshed.
The changed does not mean when child properties are changed, but when you change the item at any index.
So when you modify a collection item you will need to notify the binding that the property was changed. From your window's viewmodel after you have modified the item in the collection, you would notify that the collection was changed.
NotifyPropertyChanged("AllEvents");

Textbox binding with trigger

I need to bind the text box with the data available on it and execute a command associate with that. I want the data entered as well command execution only when "Enter" button on keyboard is pressed. I used to the below code, but it seems, I am getting command execution without "Enter" is pressed also found that for each number or text pressed, I am getting the command. I don't want this to happen.
my InputDataTemplate.xaml code:
<Label Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Content="{Binding Name}" />
<Label Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Center" Content="{Binding Value}" />
<TextBox Grid.Column="1" Width="60" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Data}" DataContext="{Binding}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged" >
<ei:CallMethodAction TargetObject="{Binding}" MethodName="IpDataTrig" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
I can understand EventName="TextChanged" plays a role here. But not sure about the other stuffs.
My TesterView.xaml code:
<UserControl.Resources>
<DataTemplate x:Key="InputDataTemplate" >
<local:InputDataTemplate DataContext="{Binding}" />
</DataTemplate>
</UserControl.Resources>
<Grid Grid.Row="2" Background="AliceBlue" >
<Label Content="Input Datas" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
<Border Grid.Row="3" BorderBrush="Black" BorderThickness="0,2,0,0" >
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled" >
<ItemsControl x:Name="IpDataNames"
DataContext="{Binding }"
ItemsSource="{Binding IpDataNames}"
ItemTemplate="{DynamicResource InputDataTemplate}" />
</ScrollViewer>
</Border>
my TesterViewModel.cs:
private ObservableCollection<InputDataService> _IpDataNames;
private InputDataService l_IpDataNames;
_IpDataNames = new ObservableCollection<InputDataService>();
public ObservableCollection<InputDataService> IpDataNames
{
get { return _IpDataNames; }
set
{
IpDataNames = value;
}
}
InputDataService.cs:
public class InputDataService : BindableBase
{
public string Name { get; set; }
public string Value { get; set; }
public string Data { get; set; }
public void IpDataTrig()
{
Debug.WriteLine(string.Format("\nInput Data {0} Updated : {1} : {2}", Name, Data, Value));
}
}
Possible duplicate question: https://stackoverflow.com/a/10466285/475727
BTW, nothing is wrong about capturing KeyPress event and calling command from codebehind. It is not violation of MVVM pattern.
Sometimes I use my own behavior implemented as attached property. Big advantage is, that I can use it in styles.
This behaviour update binding source on text property and then calls command. (TextBox.Text binding is updated on losf focus by default)
public static class TextBoxBehaviour
{
public static readonly DependencyProperty CommandOnEnterPressedProperty = DependencyProperty.RegisterAttached("CommandOnEnterPressed",typeof (ICommand),typeof (TextBoxBehaviour),
new FrameworkPropertyMetadata(CommandOnEnterPressedPropertyChanged));
private static void CommandOnEnterPressedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sender = (TextBox) d;
sender.KeyDown -= OnKeyDown;
if (e.NewValue is ICommand)
{
sender.KeyDown += OnKeyDown;
}
}
private static void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
var tbx = (TextBox) sender;
var textBindigExpression = tbx.GetBindingExpression(TextBox.TextProperty);
if (textBindigExpression != null)
{
textBindigExpression.UpdateSource();
}
var command = GetCommandOnEnterPressed(tbx);
if (command.CanExecute(null)) command.Execute(null);
}
}
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static void SetCommandOnEnterPressed(TextBox elementName, ICommand value)
{
elementName.SetValue(CommandOnEnterPressedProperty, value);
}
public static ICommand GetCommandOnEnterPressed(TextBox elementName)
{
return (ICommand) elementName.GetValue(CommandOnEnterPressedProperty);
}
}
and usage
<TextBox Text="{Binding SearchTerm, UpdateSourceTrigger=Explicit}"
my:TextBoxBehaviour.CommandOnEnterPressed="{Binding SearchCommand}"/>

ListBox item from another ListBox

On my Windows Phone app, i have two ListBox. I need that when keep an item pressed (from ListBox1), the item populates the ListBox2.
So, my LisBox1 is populated from JSON (binding).
The code bellow doesn't works (Error: Value does not fall within the expected range.):
public void addToList2(object sender, System.Windows.Input.GestureEventArgs e)
{
var dcs = ((FrameworkElement)sender).DataContext;
Fields fi = (Fields)dcs;
List2.Items.Add(fi);
}
ListBoxes:
<ListBox Name="List1" Hold="addToList2" ItemsSource="{Binding Items}" Margin="0,85,0,0" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="242" />
<ColumnDefinition Width="128" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Margin="0,0,-62,17" Grid.ColumnSpan="3">
<StackPanel.Background>
<SolidColorBrush Color="#FF858585" Opacity="0.5"/>
</StackPanel.Background>
<TextBlock x:Name="NameTxt" Grid.Column="0" Text="{Binding descricao}" TextWrapping="Wrap" FontSize="20" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Grid.Column="1" Text="{Binding valor_preco_a, StringFormat=N2}" TextWrapping="Wrap" Margin="45,20,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
<TextBlock Grid.Column="3" Text="{Binding codigo}" TextWrapping="Wrap" FontSize="35" Margin="370,-50,12,0" Style="{StaticResource PhoneTextNormalStyle}" Foreground="Blue"/>
</StackPanel>
<TextBlock Grid.Column="0" Text="R$" Margin="15,48,158,17" Style="{StaticResource PhoneTextSubtleStyle}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<ListBox Name="List2" HorizontalContentAlignment="Stretch" Grid.ColumnSpan="3" Margin="0,182,-66,0" Visibility="Collapsed">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Height="100">
<StackPanel.Background>
<SolidColorBrush Color="#FFE8FF00" Opacity="0.2"/>
</StackPanel.Background>
<TextBlock Grid.Column="0" Text="{Binding descricao}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<Listbox x:Name="listbox1" ItemsSource="{Binding listOneObjects}"
SelectedItem="{listOneSelectedItem}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="PressAndHold">
<i:InvokeCommandAction Command="{Binding TouchDownCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Listbox>
<Listbox x:Name="listbox2" ItemsSource="{Binding listTwoObjects, Mode=TwoWay}"
SelectedItem="{Binding listTwoSelectedItem, Mode=TwoWay}">
</Listbox>
Your C#
using System.ComponentModel;
public class YourClassName : INotifyPropertyChanged
private List<Object> _listOneObjects;
public List<Object> listOneObjects
{
get{ return _listOneObjects; }
set{ _listOneObjects = value; OnPropertyChanged("listOneObjects"); }
}
private Object _listOneSelectedItem;
public Object listOneSelectedItem
{
get{ return _listOneSelectedItem; }
set{ _listOneSelectedItem = value; OnPropertyChanged("listOneSelectedItem"); }
}
private List<Object> _listTwoObjects ;
public List<Object> listTwoObjects
{
get{ return _listOneObjects; }
set{ _listOneObjects = value; OnPropertyChanged("listTwoObjects "); }
}
private Object _listTwoSelectedItem
public Object listTwoSelectedItem
{
get{ return _listTwoSelectedItem; }
set{ _listTwoSelectedItem= value; OnPropertyChanged("listTwoSelectedItem"); }
}
public ICommand TouchDownCommand{ get{ return _TouchDownCommand; }
private _TouchDownCommand;
public YourClassName(){
this._TouchDownCommand= new ActionCommand(TouchDownExecuted);
}
private void TouchDownExecuted(){
listTwoObjects.clear();
listTwoObjects.Add(listOneSelectedItem);
OnPropertyChanged("listTwoObjects");
}
PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String prop){
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
There are a number of moving parts here so you'll need to know the following.
Databinding
Command Binding
Interaction Triggers
Event Triggers
Binding Modes
object myItem;
public Form1()
{
InitializeComponent();
listBox1.Items.Add("Paul");
listBox1.Items.Add("George");
listBox1.Items.Add("Nik");
}
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
myItem = listBox1.SelectedItem;
listBox2.Items.Add(myItem);
}
Like that you can obtain whatever object is in listbox1 and show it in listbox 2. Just by clicking it with the mouse
Another answer is :
This is worth a read...
http://msdn.microsoft.com/en-us/library/ms171548.aspx
SendKeys.Send("r")
This might just fire once, you may want to attach a timer that starts on the MouseDown event and stops on the MouseUp event. Then you could put the SendKeys in the Timer.Tick event.
private void Form1_Load(object sender, EventArgs e)
{
this.timer1.Interval = 500;
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
timer1.Stop();
this.Text = "moose-Up";
}
private void button1_MouseDown(object sender, EventArgs e)
{
timer1.Start();
this.Text = "moose-Down";
this.richTextBox1.Select();
}
private void timer1_Tick(object sender, EventArgs e)
{
SendKeys.Send("r");
Debug.Print("tickling");
}
Select the control that you wish to receive the SendKeys value...

Categories