Generic UserControl Using Reflection and Generalization - c#

in my project i've wrote some UserControl, i'm trying to reuse code as much as possible.
For each Model in my project i create an UserControl that shows the CRUD (a simple form ) and another that shows the List (listBox)
Is possible to Generalize that (for different types of Models with different attributes)?
Using Generalizatione and Reflection is possible to create something like a generic UserControl_Crud and generic UserControl_List?
So in my page.xaml i can use something like
<LUC:UserContro_Crud l x:Name="EmployeeUserControl_List" />
<LUC:UserContro_Crud l x:Name="CarsUserControl_List" />
<LUC:UserContro_Crud l x:Name="FruitUserControl_List" />
and in the code behind
EmployeeUserControl_List.MyProperty.ItemsSource = EmployeetList;
CarsUserControl_List.MyProperty.ItemsSource = CarstList;
//MyProperty give me back just the listbox from my UserControl
or
FruitUserControl_List.MyProperty.ItemsSource = EmployeetList;
to show 3 lists with differnt properties
#HighCore #Nate Diamond
In that way, for any kind of my Model, i have to make a particular template. For example CrudPersonTemplate `
<!-- my crud-->
<DataTemplate x:Key="MyCrud">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,20,0,20">
<TextBlock Text="Code"/>
<TextBox x:Name="edtCode" InputScope="Number" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,20,0,20">
<TextBlock Text="Name" />
<TextBox x:Name="edtName" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,20,0,20">
<TextBlock Text="Sex" />
<TextBox x:Name="edtSex" />
</StackPanel>
</StackPanel>
</DataTemplate>
than (afeter registered it in the app.xaml as a resource) i can use it in Page.xaml just typing someting like
<ContentControl x:Name="MyTemplate" Content="{Binding}" ContentTemplate="{StaticResource MyCrud}" />
... but it's hard to manage field like "edtName" from page.xaml.cs or not? i have to write more code than using UserControl to do that...
How can I manage as well as possible this field of my form?
where is the difference with UserControl? i have to bind manually the ContentTemplate...
I'm looking for a generic solution in page.xaml, in the "view" i just want to call a generic template/userControl, and "automatically" choose the relative layout according with the object type associated in page.xaml.cs (i hope to explain it better, i apologize for my ignorance)

Related

Can you bind multiple LineSeries to an oxyplot in WPF using MVVM pattern?

I am trying to plot multiple LineSeries elements in one <oxy:PlotView /> element in WPF using C# in Oxyplot where I am using the MVVM pattern. Say I have the (hypothetical) situation that I am tracking cars with a position as a function of time. Say I have the following files:
Model
Car.cs
View
DisplayView.xaml
DisplayView.xaml.cs
ViewModel
DisplayViewModel.cs
On initialization I create three car elements (in DisplayViewModel.cs : Cars = new List<Car>{ new Car(), ...};) with their corresponding displacement vs. time data PlotData = new List<DataPoint>{ new DataPoint(0,1), new DataPoint(1,4), ...}; and CarName.
DisplayView.xaml (1):
<ListBox ItemsSource="{Binding Path=Cars}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<oxy:Plot Title="{Binding CarName}" Height="400" Width="500">
<oxy:Plot.Series>
<oxy:LineSeries ItemsSource="{Binding Path=PlotData}"/>
</oxy:Plot.Series>
</oxy:Plot>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This works as expected. It shows a <ListBox /> with the three (separate) graphs. However this is not what I am trying to achieve. I would like to do something like the following:
DisplayView.xaml (2):
<ItemsControl ItemsSource="{Binding Path=Cars}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=CarName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This displays the three individual car names as is expected, so I know I have the data source connected correctly. However, wrapping this <ItemsControl>...</ItemsControl> element with <oxy:Plot><oxy:Plot.Series>...</oxy:Plot.Series></oxy:Plot> and changing the <TextBlock /> element to a <oxy:LineSeries /> element and binding its ItemsSource property to the earlier mentioned DataPoint field yields the errors A value of type 'ItemsControl' cannot be added to a collection or dictionary of type 'collection`1'. and The specified value cannot be assigned to the collection. The following type was expected: "Series"..
DisplayView.xaml (doesn't work):
<oxy:Plot Title="Displacement plot">
<oxy:Plot.Series>
<ItemsControl ItemsSource="{Binding Path=Cars}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<oxy:LineSeries ItemsSource="{Binding Path=PlotData}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</oxy:Plot.Series>
</oxy:Plot>
I am new to the MVVM pattern - and C# and WPF programming in general - and I see the DisplayView.xaml.cs code-behind file needs to be empty. I can get the three LineSeries to display in one graph when using the code behind, but I am trying to utilize the power of MVVM. Can someone give me pointers on how I should fix this? I am just not experienced enough (yet) to play around with the code, so some explanation would be appreciated. What files do I need to add, what methods do I need to create and where do I create these? Is this even possible in the way I envision?
Kind regards,
Tom
I think I grasp the concept (after writing down my thoughts and questions in this post), so I am answering my own question. In DisplayView.xaml I added a <PlotView /> as such: <oxy:PlotView x:Name="DisplayPlotView" Model="{Binding PlotModel}" />. I also created a PlotModel in DisplayViewModel.cs, which is fine by the MVVM-pattern, as far as I understand. I loop through Cars to add the different series by doing:
foreach(Car car in Cars)
{
PlotModel.Series.Add(car.PlotData);
}
Where I now made the PlotData a LineSeries in the Car.cs. This shows the three lines in one graph.

Any similar "ListView" UI Control in Xamarin.Mac?

I'm planning to design an multiple file downloader app (similar to IDM or Transmission) for macOS based on Aria2 JSON-RPC and C# GUI via Xamarin.Mac. But there is a major issue for UI design. I need a UI control which is similar to "ListView" in XAML.
Basically it's something like in this topic discussed, i.e. I need something equivalent in Xamarin.Mac with this XAML code below:
<ListView x:Name="DownloadItemList">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding DownloadItemTitle}"
Margin="20,0,20,8"
FontSize="24"
FontStyle="Italic"
FontWeight="SemiBold"
Foreground="DarkBlue" />
<TextBlock Text="{Binding DownloadProgressInfo}"
Margin="20,0,20,8"
FontSize="16"
Foreground="DarkGray"
Opacity="0.8" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I also need some data bindings in the UI code if possible. But so far I can't find any similar stuff in Xamarin.Mac. Is there any possible solution like this? Thanks in advance!
You can use NSTableView
static Content :
You can design cells from storyboard, and if required can modify content of these cells at runtime.
Dynamic Content : You can crate template cell at design time (or progrmmatically id requried ), give it identifier and use that cell multiple-time in tableviewd atasource.
You can use something like a table view
Hope this helps.
Link

Using Icons in WPF Database Driven Application Results

I am attempting to make a WPF application. The application needs to use a "list view" to show results of queries to the database. I have been able to successfully create the application (GUI, database, LINQ, etc.), however, the display of my query results appear more "gridlike".
The specifications for the project below show that each record that appears in the results needs to have a green circle icon next to it. I have removed the actual results from the images below to keep the contents of the database private.
I don't have enough Reputation Points to post images, so I posted pictures so a sample/testing domain that I use. You can see screenshots here of the WPF app and code here:
http://digitalworkzone.com/WPF.html
What am I doing incorrectly? Is there something I need to add or modify to my code to be able to get the green circles and more of a "list" style to display my query results?
Understand the WPF content model. http://msdn.microsoft.com/en-us/library/bb613548.aspx
Anything that has a 'Content' property basically behaves in two ways. If the 'Content' is set to something that derives from UIElement, then the class will manage it's own presentation. Anything else, however, will just get .ToString() called, and it's text displayed instead.
What this means in the long run is that everything in WPF can display anything. If you want to show a button in a button, you can. For example:
<Button>
<Button.Content>
<Button Content="This will show as text" />
</Button.Content>
</Button>
The inner button will have text, but the outer button will show a Button because Button derives from UIElement and therefore will handle its own presentation.
In your picture examples above, you have ListBoxes/DataGrids that you want to fill in with graphical information. Try this out:
<ListBox HorizontalContentAlignment="Stretch">
<ListBox.Items>
<Button Content="One"/>
<Button Content="Two"/>
<Button Content="Three"/>
<Button Content="Four"/>
</ListBox.Items>
</ListBox>
Now you have a ListBox that shows Buttons instead of Text. You can take this a step further and contain the items in a stackpanel, for example:
<ListBox HorizontalContentAlignment="Stretch">
<ListBox.Items>
<StackPanel Orientation="Horizontal">
<Button Content="A button"/>
<Label Content="Some text" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="A button"/>
<Label Content="Some text" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="A button"/>
<Label Content="Some text" />
</StackPanel>
</ListBox.Items>
</ListBox>
Now we have items that contain a layout container (StackPanels, which then contains other elements).
However, if you set the ItemsSource elsewhere, you can actually use a DataTemplate to display the contents. A DataTemplate in effect targets a particular class and lays out it's contents as defined in XAML. Consider:
Code Behind:
public partial class MyWindow : UserControl {
public MyWindow() {
InitializeComponent();
MyListBox.ItemsSource = new List<Person> {
new Person("Sam", "Smith"),
new Person("Jim", "Henson"),
new Person("Betty", "White"),
};
}
XAML:
<ListBox HorizontalContentAlignment="Stretch" x:Name="MyListBox" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Label Content="{Binding FirstName}"/>
<Label Content="{Binding LastName}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now when the Listbox displays, it will cycle through each of the items in the ItemsSource property, and then lay them out using the DataTemplate. It's possible to have the DataTemplate target specific classes by using the DataType property if you're using polymorphism (as in different types of people such as 'Cusomters' or 'Employees' which all derive from 'Person).
The problem with this approach is that you are setting the value of the items directly, which is bad form. It's better to define a class that handles all of the data for your view separately. Consider:
public class ViewModel {
// WPF will automatically read these properties using reflection.
public List<Person> People {
get {
return new List<Person> {
new Person("Sam", "Smith"),
new Person("Jim", "Henson"),
new Person("Betty", "White")
};
}
}
}
That will hold all the data for the view, now let's add it to the actual window. First we need to reference the namespace ('xmlns' means xml namespace):
<Window x:Class="Sharp.MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:lol="clr-namespace:Sharp">
The namespace is Sharp (the namespace where my stuff lives), and the alias we'll give it is lol. Now we attach our ViewModel class to the window by setting it to the DataContext property, as in:
<Window>
<Window.DataContext>
<lol:ViewModel />
</Window.DataContext>
</Window>
This makes all of the public properties on the ViewModel class available to the Window. This way, if we want to read the Persons information into our ListBox, we simply say:
<ListBox HorizontalContentAlignment="Stretch" ItemsSource="{Binding People}" >
...
</ListBox>
Notice that we say ItemsSource={Binding People}, which means 'scan the ViewModel for any public properties called 'People' and then retrieve those results. This is essentially the fundamentals behind the MVVM approach. You might have all of your business logic in one or many classes which handle the main application operation in a Model, but then you have a ViewModel which interacts with the Model and exposes the results as public properties. WPF automatically binds to those properties and presents them for your. The information just flows, rather than setting the values by force.
To really understand how WPF is supposed to work, you should take some time to understand the basics of MVVM. WPF was really designed with MVVM in mind, and so to really get how WPF is supposed to work, you really should take the time to get your head around it. Take a look at:
http://agilewarrior.wordpress.com/2011/01/11/simple-mvvm-walkthrough-part-i/ .
<ListBox ItemsSource="{Binding QueryResults}">
<ListBox.ItemsTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}"/>
<TextBlock Text="{Binding TextSource}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemsTemplate>
</ListBox>
Will work if you have a list of objects named QueryResults in your code behind. Each object needs to have an string property named ImageSource and a string property named TextSource.
However, since you only need to display a green circle icon for each of the items, you can hardcode the image source. The above will work if you want to have a different icon for each, though.
Also note that in order for this to work, you need to set the DataContext of the window to DataContext="{Binding RelativeSource={RelativeSource Self}}"

LongListSelector with two ItemTemplate

I use this code to add ListBox to my app:
<phone:LongListSelector x:Name="searchList" Margin="0,72,0,0" SelectionChanged="DidPressSelectSearchList">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,20,0,0">
<TextBlock Text="{Binding}" FontSize="25" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
Now my issue is that i want to use two kind of ItemTemplate, because there is two ways i show data to the user:
1) Array of Strings
2) Array of objects(2 Strings)
Any help how i can use the list to show two kind of objects?
The easiest way to do this in WP7 is with a Template Selector.
Like this one
Though I cant test it right now, WP8 should support the DataType property on the DataTemplate class, which means you can define implicit Data Templates for each data type and skip the selector altogether.

WPF MVVM and View inheritance

I have about a dozen different views, which are pretty much identical except for the names of the properties they bind to. For example, the below sections are form two different views:
<TextBlock Text="{Binding PersonName}">
<GroupBox Header="{Binding PersonName}">
<ComboBox Text="{Binding SelectedPersonName}" SelectedItem="{Binding SelectedPerson}" ItemsSource="{Binding People}" DisplayMemberPath="PersonName"/>
</GroupBox>
<igDP:XamDataGrid DataSource="{Binding PersonEntries}"
<TextBlock Text="{Binding CarName}">
<GroupBox Header="{Binding CarName}">
<ComboBox Text="{Binding SelectedCarName}" SelectedItem="{Binding SelectedCar}" ItemsSource="{Binding Cars}" DisplayMemberPath="CarName"/>
</GroupBox>
<igDP:XamDataGrid DataSource="{Binding CarEntries}"
Note that the only real differences between these to blocks are the names of the bindings used (Person vs Car).
I was thinking of maybe creating one BaseView class that the other views inherit from. This base class would use generic enough binding names so that it can be reused, such as:
<TextBlock Text="{Binding DataItemName}">
<GroupBox Header="{Binding DataItemName}">
<ComboBox Text="{Binding SelectedDataItemName}" SelectedItem="{Binding SelectedDataItem}" ItemsSource="{Binding DataItems}" DisplayMemberPath="DataItemName"/>
</GroupBox>
<igDP:XamDataGrid DataSource="{Binding DataItemEntries}"
This way, my PersonsView and CarsView can inherit from BaseView and that's it. I would also have to make changes to the ViewModels though, so that they expose the correctly named properties, such as DataItem. I guess I could create a base ViewModel interface that exposes the desired properties and have the other ViewModels implement that.
Any thoughts on the above? Would it be a bad idea to try to create a base view or base view model as I described?
Thanks.
You're really going to create the inheritance in your view models, not your views. I'd define an ItemViewModelBase class that exposes ItemName, Items, and SelectedItemName properties and derive my view models from it.
The views themselves don't really "inherit" per se. In fact, unless you need customization in the view, you don't need multiple views: you only need one view that presents ItemViewModelBase objects.
Of course, if you do need the views to be different, you can do a certain amount of customization, e.g.:
<DataTemplate DataType="{x:Type CarsViewModel}">
<DockPanel>
<Label DockPanel.Dock="Top">Cars</Label>
<local:ItemView/>
</DockPanel>
</DataTemplate>
This is a cool idea for another reason. Right now, if you don't provide a data template, whenever WPF presents an object it creates a TextBlock containing object.ToString(). Implementing a generic base class gives you a way to globally override this behavior just by creating one data template, e.g.:
<DataTemplate DataType="{x:Type ItemViewModelBase}">
<TextBlock Text="{Binding ItemName}"/>
</DataTemplate>
That's not easier than just overriding ToString() to return ItemName (which is where I'd start), but if (for instance) you want a ToolTip that displays detailed information when the user mouses over it, you just add it to this one template and it works everywhere in your UI.
May be you can continue having one generic view model, but having, instead, multiple
data layers. This can basically help you to push complexity on data layer,which
is basically easier to test and debug. But everything is too context dependent.
Good luck.

Categories