Using a non-static UserControl without using as an object - c#

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();

Related

ListView in Avalonia UI

Unfortunately Avalonia UI is still behind WPF and ListView is missing. I have found out one alternative, ItemsRepeater, but its very basic and not interactive. Apparently you can make it interactive, but I have to yet found an example that takes less than 200 lines of code and actually works. I just refuse to believe no one made something that works as simply as ListView in WPF.
I want to display List of custom data model (property A and B etc), and I'm really tempted to just use DataGrid. Will be ugly, but it will work.
You can try https://github.com/wieslawsoltes/DataBox it's very simple control with columns based on ListBox

WPF Thread binding access error on binding in MVVM

So I am trying to incorporate dynamic-data-display for WPF into my MVVM caliburn project (I am using the LineChart control from future of dynamic data display, if anyone wishes to test this error). There is a LineChart that binds to an ObservableCollection. It only works if the collection is made in the code-behing of the control which has the LineChart. If you try to bind to a collection the ViewModel the dependency property raises an InvalidOperationException. How can this problem be solved?
I have seen that happen when you change the collection which the property is binded to and know ways to fix that, but never in the actuall proccess of binding. I've tried putting the creation of the collection in a dispatcher invoke (like you wold do with an add or remove) but it didn't help.
Edit: As I stated in the second paragraph the exception is NOT at the point of changing the collection. It is being raised at the point of binding. Even more, I have tried to use the solutions in the other question and they did not help.
Edit #2: The exception message is "The calling thread cannot access this object because a different thread owns it".
People keep telling me solutions to collection changes but it doesn't even get to the changes. It fails at binding stage (ItemsSource="{binding collection}" in xaml).
Edit #3: I double-checked and noticed that the ViewModel is created in the UI thread which only made more questions.
Ok, it took me quite a while to find the root cause of your problem.
Unlike from what others suspected, this isn't a multithreading issue at all.
Instead it's an issue with the DynamicDataDisplay library you are using.
There's a clear reason why your ItemsSource binding works on your ListBox object and doesn't work on Chart (of type Microsoft.Research.DynamicDataDisplay.Markers2.LineChart) :
Chart neither has a visual nor a logical parent.
You can check this if you insert the following code into Button_Click and set a breakpoint after them:
var visualParent = VisualTreeHelper.GetParent(Chart);
var logicalParent1 = Chart.Parent;
var logicalParent2 = LogicalTreeHelper.GetParent(Chart);
You can see that they are all null.
So the Binding that you set on LineChart.ItemsSourceProperty with Path=ExampleCollection cannot find any source value and just assigns null to the ItemsSource. That's because the DataContext is inherited from the parent - but when there isn't any parent then there isn't any DataContext to inherit either.
And because Chart isn't part of the visual or logical tree, there is no (easy) way any binding to an outside DataContext can even work.
To verify that the DataContext is null just add this line to the preceding code:
var dataContext = Chart.DataContext;
Now there are three possible solutions for this.
First, you can manually inherit the DataContext from Window using the following code:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Just add the following line.
Chart.DataContext = DataContext;
Chart.StrokeThickness = 3;
Chart.SetBinding(LineChart.ItemsSourceProperty, new Binding("ExampleCollection"));
// ...
}
If you simply add this one line, you'll see that your other multithreaded code is working just fine and the chart is updated with some kind of sine wave pattern.
Second, as another possible solution you can consult the documentation for the DynamicDataDisplay library and check the correct and intended way to assign an ItemsSource to a LineChart using data binding.
I tried searching for documentation myself and even debugged a lot of code from that library for two hours or so, but the documentation is nearly non-existent and the code is far too complex to fully understand it in a few hours. I tried using several tools (Visual Studio Live Visual Tree, Snoop, ...) for displaying the visual tree of the ChartPlotter but I got a StackOverflowException every time, so essentially something in this library is kind of flawed and buggy.
Third, you can use a Resource as a kind of proxy object to create a "binding bridge" to the same instance of the MainWindowViewModel.
For this to work, you have to do something like suggested here: Data binding outside the visual tree. Data Context bridging
Bottom line: So, if you just want to get the job done, I would set the DataContext in code like shown above. (Especially if the instance of the ViewModel in the DataContext never changes.)
If you want to use pure data binding then I would probably use the "binding bridge" or search for another charting library that supports this scenario.
As THIS thread states you can use the UI dispatcher and invoke the function that changes your ObservableCollection on the UI thread. Application.Current.Dispatcher should give you the UI dispatcher. As the solution suggests it can be right in the ViewModel. However, a cleaner and more generic solution is to IMPLEMENT a concurrent and still observable collection it would still store the dispatcher and run the changes on the UI (or specified) thread.

WPF Control Identification

Sorry but I am a newbie to WPF, I would really appreciate if you could help me-
Tag 1 in pic- Which control can I use to create a menu similar to that in the picture ? The closest I came was using a gridview within a listview but that ends up using a header for the gridview. Normal listview just highlights the entire strip and doesn't look good at all.
Tag 2 in pic // (No longer relevant, sorry)
Edit:
Looking for something simple like when using gridview with listview (as in pic below) there is automatically that standard window gradient & bevel effect etc. (As an idea, implementing it with buttons seems to cumbersome, first strip button border, then create all these effects.) So essentially anything already inbuilt in WPF.
Thanks for any help :-D !!!
ListBox or ListView are good controls to use. If it's just the 'pretty' factor you don't like, you can provide Templates to change the appearance. But functionally, ListBox and ListView provide the function of that menu.
When working with WPF, that should be your primary motivation when choose controls. What FUNCTIONS the way you want. You can always make it LOOK different with Templates, but getting the right FUNCTION is the primary goal for the control.

TabControl Deep Copy

I need to make a deep copy of a tabcontrol.
The large picture is this: I have a project which has a 300 line XAML code TabControl with 8 tabs in it which are pretty big. I also have a TreeView with different items.
When an item in that list is selected it shows the TabControl associated with it. The problem now comes that when I add an element I want to make a deep copy of the original TabControl and associate that new one to the new element (of course I'm going to erase the content in the new one). Shallow copies won't work because they are pointing to the same location in memory, so "=",IClonable are a no go. And the frustrating part is that I can't use deep copy with serialization because the TabControl is not serializable. And I can't (or should say won't) make a custom TabControl which is serializable because the TabControl is 300 line in XAML and it would be 600 line in code so it's a waste of space and time.
I've searched for this for 2 days and didn't find anything. There is no need for me to show the code because I'm looking for a general purpose Deep Copy method that can copy any type of a TabControl.
You're doing it all wrong.
You're not supposed to "copy" the UI or whatever, because UI is Not Data. You should be manipulating and copying Data Items instead of UI elements, and probably using DataTemplates to have your Data items represented on screen.
I strongly suggest that you research and learn MVVM before ever writing a single line of code in WPF.
After searching some more I initially tried a different way but it turned out to be more trouble than it's worth (tried with data binding and working more in code but still to much).
So the solution is to use XamlReader and XamlWriter. Official documentation is found here and respectively here !
To answer my question in code it would be:
Say you had this tabcontrol in XAML here:
<TabControl>
<TabItem><!--A lot of stuff here--></TabItem>
<TabItem><!--More stuff here--></TabItem>
</TabControl>
And remember this is if you have a lot of stuff (basically I didn't mention this but I'm making an interface that creates a pretty complex XML so in that TabControl I'm handling a lot of user generated data)! If you have a simple TabControl just make a custom one in code or simply use DataBindings.
So the code in the background for making a Deep Copy of that XAML defined TabControl would be this:
string savedTabControl = XamlWriter.Save(originalTabControl);
StringReader stringReader = new StringReader(savedTabControl);
XmlReader xmlReader = XmlReader.Create(stringReader);
TabControl newTabControl = (TabControl)XamlReader.Load(xmlReader);
So this is basically serialization made on xaml controls and not on data.

Getting the SelectedItem as DataContext for a completly independent Uielement

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)

Categories

Resources