Retrieve treeview item - wpf

In my treeview I have text. After I select that, I want to retrieve that selected item as string and I need to pass this string to various functions.
I don't know how to get the selected item.I coded like
private void treeview1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
TreeViewItem selectedTVI = null;
if (treeview1.SelectedItem != null)
{
selectedTVI = treeview1.Tag as TreeViewItem;
}
}
But selectedTVI shows NULL.What can I do?

TreeViews display lists of items, not lists of TreeViewItems.
TreeViewItem.SelectedItem is the element that is selected, if your tree view has a collection of Car objects that it is displaying, the SelectedItem will be of type Car.
try this
private void treeview1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (treeview1.SelectedItem != null)
{
Console.WriteLine(treeview1.SelectedItem.ToString());
}
}
im pretty sure the SelectedItem is the object you are looking for.
(by the way your 20% acceptance rate sucks a little - and is probably one of the reasons you dont get your questions answered quicker, if your question is answered, mark it as answered. This helps the whole community)

Related

WPF DataGrid: Making an entire column unselectable

I have a DataGrid which holds a few columns, some of them shouldn't be selectable to the user (since they're read-only anyway).
There is no property for the column itself, apparently I need to handle this through the SelectedCellsChanged-Event.
I can use an IF-statement to find out whether the corresponding column of a cell is non-selectable by doing something like this:
private void chartDataGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
if (e.AddedCells[0].Column.Header.ToString() == "Non Selectable Column")
{
// What now?
}
}
How do I keep the cells in this collection from getting selected, though?
Alright, I got it. It may not be the perfect solution, but it works flawlessly for me. Even with lots of cells AND when selecting cells from several columns containin ones that should be selectable. :)
private void chartDataGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
foreach (DataGridCellInfo cell in e.AddedCells)
{
if (cell.Column.Header.ToString() == "NonSelectableColumn")
{
MyDataGrid.SelectedCells.Remove(cell);
}
}
}

WPF ListView with ItemsSource: how to know when model adds item

Question: What is "proper" way of letting the user control's "view model" (.xaml.cs file) know that a ListViewItem has been added to a ListView? Note that this post is addresses a different problem.
Details:
I have a UserControl which contains a ListView and a DataContext:
The ListView has an ItemsSource={Binding ActionLogEntries}
ActionLogEntries is an ObservableCollection property in the DataContext
The data context adds items to the ListView when certain things happen.
But there isn't a ListView.ItemAdded event. There is a CollectionChanged event on ObservableCollection in data context but the view model's handler of this event could get called before the item is added to the ListView so this doesn't seem like a good strategy.
FYI: This came up because when items are added to the ListView, it doesn't automatically scroll to the newly added item, which is behavior I have to add. Presumably I'd use ScrollIntoView after that.
So there are at least two ways of skinning this cat:
do as explained by Clemens in comment to my question
do as in this post by WPF Mentor
Solution 1 seems more natural for the event subscription, since you don't need to cast; also IntelliSense doesn't show class members of implemented interfaces without cast, so for Solution 2 you have to remember to look at what interfaces are implemented and check for events there too. Here is what the subscription looks like for each solution:
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
// Solution 1, subscription:
xActionListView.ItemContainerGenerator.ItemsChanged +=
new ItemsChangedEventHandler(ActionLog_ItemsChanged);
// Solution 2, subscription:
((INotifyCollectionChanged)xActionListView.Items).CollectionChanged +=
new NotifyCollectionChangedEventHandler(ActionListView_CollectionChanged);
}
But solution 2 has easier to use event arg in handler:
// Solution 1, handler:
private void ActionLog_ItemsChanged(object sender, ItemsChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
// Solution 1, scroll the new item into view
xActionListView.ScrollIntoView(
xActionListView.Items[e.Position.Index + e.Position.Offset]);
}
}
// Solution 2, handler:
private void ActionListView_CollectionChanged(
object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
// Solution 2, scroll the new item into view
xActionListView.ScrollIntoView(e.NewItems[0]);
}
}
It looks like in some circumstances, one solution may be more appropriate than the other: the event data may be easier to use in one or the other based on what data you need.

ListView Insert new item on TAB

Having a WPF ListView with items bound to a data object and represented by editors (Text, DateTime, etc.). I would like to be able to insert a new item when the users is in the last editor at the last item and presses TAB. Then after set input focus to the first editor of the newly added item.
Thus far I have this:
private Boolean _tabAddedNewSpec = false;
private void OnBaseEditKeyDown(object sender, KeyEventArgs e)
{
if (!_tabAddedNewSpec)
{
if (e.Key == Key.Tab)
if (this.listview.SelectedItem == this.listview.Items[this.listview.Items.Count - 1])
{
this.AddSpec();
// No further tabbing out of this control, we manage it ourselves in this special case...
e.Handled = true;
_tabAddedNewSpec = true;
// Select last item (is NEW one)
this.listview.SelectedItem = this.listview.Items[this.listview.Items.Count - 1];
}
}
}
private void OnBaseEditKeyUp(object sender, KeyEventArgs e)
{
if (_tabAddedNewSpec)
{
((BaseEdit)sender).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
_tabAddedNewSpec = false;
}
}
This code almost does the trick. But, I don't allow that a spec (specification) is added when there are other specs that contain validation errors (on the business object). The problem is that when pressing TAB the editvalue on the last editor isn't yet passed to the business object. Then when calling this.AddSpec() results in nothing because it detects that there are still errors. Follow me still...
And by the way, this solution seems pretty dirty to me. Anybody good advice? Very welcome!
As mentioned before, the solution nearly did the trick. With first updating the binding of the active control the desired solution was produced. Using this code:
BindingExpression bindingExpression = ((BaseEdit)sender).GetBindingExpression(TextEdit.TextProperty);
if (bindingExpression != null)
bindingExpression.UpdateSource();

WPF Drag & Drop of integer into datagrid of object

I have a datagrid in a window of my WPF MVVM Applicatiion, in another window I have a datagrid of another type of object.
As long as the two objects in the different datagrids matches, then there is no problem. But in this occasion I have two different objects in these windows.
What I want to do in my target window is that in my code behind change the object in the DragEvent to the object that matches the recieving grids object, something like this:
void dgdIngredient_PreviewDrop(object sender, DragEventArgs e)
{
if ((e.Data.GetData("**MyTypeOfObject**",true) as VMProductComponent) != null)
{
VMProductComponent vmp = new VMProductComponent();
e.Data.SetData((e.Data.GetData(typeof(object)) as FOODit.Matilda.ViewModel.VMProductComponent));
}
}
However, the conversion always fail, and I allways get null in my GetData() statement, can anyone help me get this right, if it is even possible.
Thank you in advance.
/Peter
Seems as though I had been working for too long, I was trying to convert my source object to my target object directly, so this is the correct solution.
private void target_Drop(object sender, DragEventArgs e)
{
MyTargetType data = e.Data.GetData(typeof(MyTargetType)) as MyTargetType;
if (data != null)
{
target.Content = data;
}
}
/Peter

How to have separate pages databound?

I'm wanting to use a datasource to go through records but one at a time per page.
So I'd like a whole page to be dedicated to a single record.
How would I do that?
Easiest way is just swap out the DataContext on the page. So don't bind to the list, bind to individual items in list.
private List<Question> _questions = new List<Question>();
private int _currentItem = 0;
private void nextButton_Click(object sender, RoutedEventArgs e)
{
_currentItem++;
this.DataContext = _questions[_currentItem];
}
private void backButton_Click(object sender, RoutedEventArgs e)
{
_currentItem--;
this.DataContext = _questions[_currentItem];
}
Now obviously you would have to add bounds checking to make sure you don't go past the last question, or before the first question, but you get the idea.
If you are using MVVM the idea is pretty much the same - you want the viewmodel to model a single item rather than the list of items, then you just swap the data for that current item as you navigate forward or backwards.

Resources