Getting the SelectedItem as DataContext for a completly independent Uielement - c#

I began to make a program in c# using wpf and the mvvm pattern to learn this program language. I feel sorry that I finally have problems I can't solve using Google. But I try being precise.
At first I present you the GUI, so I can explain my problems more easily.
The xaml file of the MainWindow comes here.
As you see, it's not a serious and important program, I just made it to learn some techniques.
Now comes my main question:
I need the SelectedItem Property of the second ListView(Consumables) in the footer. I thought this wouldn't be a serious problem cause I can just bind it to the selected item using relative path and the name of the listview. This didn't work and caused a null reference error as soon as I added an item to this listview. I double checked the code and I am sure I haven't made something wrong there. So I thought the problem is, that it's kind of a descendant ui element.
My next try was to create a new property in my main view model which is bound to the selected item. You can find this in line 136. But as I found out, this causes me a System.NullReferenceException too if i click on an item. I think it's because this property is read only. I don't know what to do. Isn't there any other possibility to bind the SelectedItem as DataContext for the footer?
My Second Question is about line 27. The TabControl should always select the first Tab automatically. But it makes it only every second time. It's quite funny. If I scroll down the Champion Combo Box, the first tab goes: selected - unselected - selected - ...
My third and last Question is about 72 which is similar to line 50 (The DataContext is the same too) But the ICommand of the ContextMenu of the itemtemplate you see line 50 works, whereas the contextmenu (l. 72) does not call the Icommand. Weird.
It's a fun project, so I can provide you the source code if my information are not enough.
--Sorry, only two hyperlinks allowed--
Please help me. I am just a bit confused by this unsuspected behaviour. I haven't found anything that could help me and I'm sorry if the answers of these questions will be simple :P
Just to emphasize it: The main question is the only one I really need an answer for. The second one could be solved programatically. And to solve the third one, I could just remove this feature.
I'm happy for EVERY HINT!

Haven't gone through the entire question but you should bind selected item to your view model property (two way binding) and then bind another UIElement to this view model property (probably one way binding or check for value equality as to not cause stackoverflow exception)

Related

WPF ListBox.SelectedItems as ListBoxItem

Is there a way to have the selected items of a ListBox as a ListBoxItem in the event SelectionChanged (on the ListBox) in WPF?
Right now, when I call listBox.SelectedItems I get the list of items in the format of my data source.
For example, when I create my ListBox I bind it to a CustomListBoxViewModel as a data source, so when I called SelectedItems I get a list of CustomListBoxViewModel objects.
Thanks!
EDIT:
The code that was given in the chosen answer worked perfectly for my use case.
On the other hand, I completely understand that this is a violation of the MVVM pattern. I'll use the code you provided in code behind of a xaml view.
The reason behind my original question was that I need to implement a ListBox that has some disabled ListBoxItems inside. Those items would have to be unselectable.
I tried to use an Attached Property IsSelectable on my ListBoxItems and it didn't work well. This attached property was greatly inspired by this post. The problem was that when I was directly selecting a disabled item, the attached property worked perfectly. The item couldn't be selected and it wasn't inside the SelectedItems collection. But if I wanted to select all the items by pressing CTRL+A, all the ListBoxItems were selected even the disabled ones and were found in the SelectedItems collection.
Whatever reason you're doing this for, it's probably a serious violation of MVVM that you'll bitterly regret for the rest of your life.
But the first step on the road to perdition is always an easy one.
Here's how:
var listBox = (ListBox)sender;
var selectedListBoxItems =
listBox.SelectedItems.Cast<Object>()
.Select(item => (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(item))
.ToList();
Just don't come crying to me when it all ends in tears.
No but seriously, there's are a few good reasons to do this kind of thing in WPF, but they're far less common than somebody new to WPF would expect. Pretty much any normal case is best handled by having your C# code interacting only with your data items, and do stuff to the ListBoxItems in XAML via styles and templating. Once you get used to that way of thinking, it's very powerful, flexible, productive, and maintainable. Codebehind is what you do for odd cases when all other reasonable avenues fail. Drag and drop, for example.

WPF Immediate binding to all TabControl TabItems

I am currently running into an issue where I want all of my tabs to be immediately bound to my ViewModel. For some reason, it seems that WPF doesn't bind my other TabItem's until I select them for the first time. I am eager for a solution in this because I have validation on those others tabs. Until the binding occurs on those other tabs, my app thinks everything is valid when it isnt. If it helps, I am using FluentValidation for my validation.
I have tried using someone's TabControlEx to see if that would help me but it doesn't. I also tried to cycle through all the tabs after I load the data to force the binding but that didn't always work on slower devices. I am not a fan of this solution either.
I don't know why you are being voted down, seems like a valid question, but you will still get a vague answer, due to the nature of the TabControl:
The default style for WPF TabControl only contains a single ContentControl which is used for displaying all tabs. Thus, the visual tree representing a tabs content is created on demand; and tears down to be replaced with a new visual tree when the content/tab switches.
The common issue here, is that switching between tabs becomes slow, and thus there are a couple of solutions out there:
Binding to ItemsSource of TabControl in WPF
https://github.com/ButchersBoy/Dragablz
However, what happens with the solutions is that ContentPresenters are cached...but they still wont be created until a user first hits the tab. Thus, you will still have the same issue.
Thus you need some sort of architectural change. You need your set of view models to be validated from a trigger in code, on initial startup. Waiting for the tab control to render items just isn't going to work for you.
You probably need to bubble the error up in your view model hierarchy to display in the TabItem.Header or in the window itself; perhaps you might have a MainWindowViewModel where you can display a top level error.

Using a non-static UserControl without using as an object

This question is going to be worded awkwardly as I'm finding it difficult to word it. My code is also a bit of a mess as I'm still learning C# and probably shouldn't have delved right into WPF. This may also be why I haven't found the solution with google. Anyway...
My program has a menu with a search bar, with a tab-control that separates the program into sections and each tab-item has a user-control. The user-controls are being used to keep the XAML of the main window clean. This caused the problem where I couldn't use the search bar because it was separate from the UserControl.
As the methods in the user-control can't be static, I can only think to create it using ClassName title GetItem newItem = new GetItem(). This works! Except for the fact that nothing will be displayed on the user-control (whereas MessageBox shows me that the data exists) because (I think) I've pretty much created a new user-control to what I am displaying on the program using XAML with <local:user-control>.
I'm not familiar with data binding too much, but I've tried with no success to bind the labels, because I was under the impression that by using binds, the labels will both show the same data. Is this the case and I just implemented it wrong?
Also, I imagine that by removing the the user-control being shown using XAML and instead displaying programmatically after creating it as an object would work, but I would prefer alternatives.
The easiest way I've found to get the effect I'm hoping to achieve was this.
While I added: <local:UserControl/>,
I just needed to add x:Name="InstanceName" to get:
<local:UserControl x:Name="InstanceName"/>
With this, I can replace GetItem newItem = new GetItem(); with:
InstanceName.GetMethod();

Best way to handle sequence of clicks in wpf

Let assume I have a canvas filled with rectangles, databound to a viewmodel.
Now I want to "select" a rectangle, so I've added a Select command to the rectangle class, and bound that to the rectangles.
This works fine.
The problem is this selection will have consequences. Easiest example is that selecting one rectangle should deselect any previous.
One way to deal with this would be to change the command (using relaycommands here) from
_ => this.Selected = true
to
_ => ParentVM.SetSelected(this)
This feels a bit nasty. "Loosening" the 2-way dependency by some DI framework just feels contrived in this example.
I'm guessing another way would be to solve this at the "WPF level", by using the bubbling of events, but I'm not sure that it's a better solution?
Anyone have any good suggestion?
EDIT: Got a good tip in the comments below about inheriting "Selector". This is an excellent suggestion, but unfortunately I left out a detail above, that i didn't think mattered.
The real problem is that I want to first select one of the rectangles, and then another one and get, say, the distance between them displayed. So one of them is the "first selected" and the other is the "second selected".
Unless I am not understanding the requirement, this is what I would do.
Create a property (on the VM if using MVVM) which will hold a reference to the last rectangle which has been selected.
Require each rectangle to report itself when its selected, by either, owning a bound reference to that aforementioned property or by using a commanding operation where it reports itself as the reference.
Inside the setter of the property created, take the old one (if it exists) and the new one, determine the distance and put that on another property on the VM and then hold the reference to the currently selected one.

How to a implement ListBox ScrollIntoView functionality in a ViewModel

I have a screen with a TextBox in which the user can type a 2-character state code. Below the TextBox is a ListBox containing all 50 state codes. The TextBox is bound to property in the VM, and the SelectedItem is bound to a property in the VM. That all works fine.
The way I want the UI to work is when the user selects a state from the ListBox, the TextBox is automatically filled in, and this works fine.
Where it gets messy is when the user types in the state in the TextBox. When I get the first character, what I want to do is reposition the list box at the first matching state code for that letter, so for instance, if the ListBox is sitting at "AK" (Alaska) and the user is going to type "ID" for Idaho, when I get the "I" I want to position the ListBox so you can see the first "I" state, which is "IA" (Iowa).
If I use code behind and point SelectionChanged=BringSelectionIntoView with this method coded as follows, it works great:
private void BringSelectionIntoView(object sender, SelectionChangedEventArgs e)
{
ListBox lb = (ListBox)sender;
lb.ScrollIntoView(lb.SelectedItem);
}
All I have to do is scan the list of state codes until the first letter matches, then update the Index property to which SelectedIndex is bound, and poof, the BringSelectionIntoView() method gets invoked and I have exactly the UI behavior I want.
Trying to do this in a purest MVVM methodology, however, has proved quite frustrating. I'm not using MVVMLight or ExpressionBlend--I want a simple way to do this in MVVM. I understand the purest's mindset of not putting any UI code in the view, but the framework is insanely cumbersome to enact this kind of behavior. There's a point of diminishing returns when you have to create such obtuse plumbing to force yourself to adhere to a pattern when it's far more practical to put in the method with 2 lines of code that works perfectly.
So my question is this: am I doing something wrong and is there a simple way to make this work without violating MVVM? It's disappointing if the solution requires additional SDKs or someone's framework. That would suggest that MVVM doesn't have particularly good legs to stand on in a generic OOP sense.
Does someone see an error in what I'm trying to do, or do you see a simplistic solution here? Thanks!
MVVM is not about not having any code behind.
What you're talking about here is VIEW behavior. Which fits perfectly in the code behind, as long as you're not messing with the DATA in the event handlers.
You're using a VIEW event handler to manipulate a VIEW aspect.
That doesn't break MVVM.
Keep it that way. Keep it Simple.
You should still have a ViewModel and a Model to hold the DATA that the UI shows.
This is a perfect use case for an attached behavior. You can write this behavior once and use it for all listboxes without ever having to write any additional code. If you would like me to elaborate, ask and I'll post more information.

Categories

Resources