|
Ok, so I looked at your code a few times and re-read this post. I understand what you've done here. Thanks for teaching me something. I do have some questions.
It seems to me that this is A LOT of code just to build a stand alone user control. Basically, there are now 5 components involved just to tell when the user clicked a list item in the user control. So really this isn't 'stand-alone' at all. In order to make it work there would have to be the singleton class, the User Control, and the host for the control. And, there's duplicate code in some places.
Again, I do get what you've done, but I can't believe that it takes this much effort to produce a stand alone user control.
Have I missed something here?
If it's not broken, fix it until it is
|
|
|
|
|
You are correct that there are better ways to do this. I was building off of your example... not following the cleanest way to do it. Plus, that is sort of a moving target. What you think may be the cleanest way to do it I may think isn't. So my goal was to show you one way of achieving what you wanted using the framework you had setup.
The driving factor for my example is that you have a sub-view which you put into the content of the grid in the main view. You create a view model for both the host (main) view and the sub-view. The key thing here is to understand that despite declaring the sub-view as a 'user control' it isn't a control in the traditional sense of the word. That is why DP implementation is a bad choice in this situation. In fact, I hate the "user control" terminology because I think it muddies the waters. They should have called is a "user view" instead but since the class inherits from Control I can understand the naming. So your demo had a main view and a sub view both with view models attached to them. In order to communicate between those two view models in a way that doesn't create a dependency between them requires a third party. That could be command classes, a static or singleton class (as I demonstrated), and a messaging facility. The specifics aren't as important as choosing what is right for your situation and avoiding a dependency between the view models.
Circling back around I think I'm understanding where you want to go with this and where we are missing the mark. I think you want the picker to be a CUSTOM CONTROL so you can put it on the main page and have access to the selected item as a property on that control. That is very different than the approach you took in the demo app. The architecture with the views and view models threw me.
A custom control actually has nothing to do with MVVM or view models but rather is a marriage of a code file that inherits from control and a xaml template that skins the control typically defined in /Themes/generic.xaml. In this case you can add properties and methods to the class to create the behaviors you want that control to have. That is the time to use dependency properties... but they go on the control class.
Custom controls aren't for the faint of heart. There are a number of required moving parts and some very specific requirements. I've got a three part article series that takes you from a blank project to a working custom control but it is still in draft status. I'll try to hurry up and get it published. It would be a good read for you if you want to tackle turning the picker into a custom control.
|
|
|
|
|
Jason Gleim wrote: I think you want the picker to be a CUSTOM CONTROL so you can put it on the main
page and have access to the selected item as a property on that control
[Edited]
I looked at a CustomControl, and I don't think that's it.
I'd love to see your article when you're done with it.
If it's not broken, fix it until it is
modified 9-Sep-13 14:14pm.
|
|
|
|
|
Why remove the SelectedJob property? The tree in JobListView has it's selecteditem bound to it. How would the VM know a job was selected??
This is hard to discuss without posting tons of code.
If it's not broken, fix it until it is
|
|
|
|
|
Slap my head sideways. This is what happens when I post after 3 hours sleep. With a DP, you provide a static Set... And Get... For the static reference.
|
|
|
|
|
I might be missing something, but from what I can see:
- The
TreeViewEx 's SelectedItem is bound to the SelectedJob property on the JobListViewModel ; - The
JobListView 's SelectedJob is bound to the SelectJobWindowViewModel 's SelectedJob property; - The
JobListViewModel 's SelectedJob is not connected in any way to the JobListView 's SelectedJob ;
I think you need to connect the two SelectedJob properties. Something like this should work:
public JobListView()
{
InitializeComponent();
var binding = new Binding("DataContext.SelectedJob") { Source = this };
SetBinding(SelectedJobProperty, binding);
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Please don't set data bindings via code . You get a slap on the wrist for that.
|
|
|
|
|
Hi everybody,
I live in Côte d'Ivoire (West Africa)we're (me and my friend) going to start a project in WPF concerning a drug store. But we have never programed with WPF. So we need someone to coach us.
Please help.
|
|
|
|
|
There are many excellent articles here on Code Project that will take you through the processes of creating WPF apps. Have a look at articles by Sacha Barber and Josh Smith. There's also a free ebook here[^] that teaches you how to use WPF.
|
|
|
|
|
Thanks for your reply but the file no longer exists.
|
|
|
|
|
It does. It's the internal site redirection that causes the problem. Once you've registered, just copy this[^] into your address bar and you get the download page.
|
|
|
|
|
MSDN provides a number of good material for beginners on WPF as well.
|
|
|
|
|
Hi,
I want to create virtual classroom using silverlight and implement it in my asp.net web application. I found a project named silverdraw but it is not running well. I want to create it step by step. Plese help me ASAP..
Thanks in advance
modified 4-Sep-13 7:29am.
|
|
|
|
|
|
Member 10183457 wrote: I want to create it step by step
That's good. Step by step is definitely the way to code it.
Member 10183457 wrote: Plese help me ASAP
Okay. You start off by defining what your requirements are. I cannot stress enough how important this step is. Too many people think that they should just rush in and start coding and that they don't need to do the analysis phase - this is just plain wrong. Once you have figured out what your requirements are, that's when you can start to design your application. Factor in things such as how many people you expect to use the application. The number of concurrent users. How much is being saved out to database. What bandwidth you have available to you.
|
|
|
|
|
I'm working on a WPF application that has some parts that will be run on a Windows 8 Tablet. In this app is a treeview. Clicking the nodes with the mouse works fine. But touch does not. I get no response. Buttons, lists, combos, and other controls all respond. But the treeview does not.
Any ideas?
If it's not broken, fix it until it is
|
|
|
|
|
On the TreeView , set the property IsManipulationEnabled to true.
|
|
|
|
|
Ok, it sort of works. Here's my HierarchicalDataTemplate:
<Style x:Key="{x:Type TreeViewItem}" TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
<Style.Triggers>
<Trigger Property="IsMouseCaptureWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
<HierarchicalDataTemplate DataType="{x:Type models:JobSummaryModel}"
ItemsSource="{Binding Path=Nodes}">
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Source="/FMG.UI.WPF.Shared;component/Media/Images/job_72.png"
Grid.Column="0"
Height="16"
Width="16"
Margin="0,0,3,0"/>
<TextBlock Grid.Column="1"
Text="{Binding Caption}"
IsManipulationEnabled="True"/>
</Grid>
</HierarchicalDataTemplate>
and then my TreeView:
<controls:TreeViewEx BorderThickness="0"
ItemsSource="{Binding Nodes}"
SelectedItemEx="{Binding SelectedTreeNode, Mode=TwoWay}"
IsManipulationEnabled ="True">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>
</TreeView.ItemContainerStyle>
</controls:TreeViewEx>
The tree is one to many, meaning each parent can have one or more children. Sometimes when I click a parent node it is selected. The VM sets the IsExpanded to true if a parent node is selected.
But I have to touch all over the node area many times to actually get it to select. And sometimes it never does.
If it's not broken, fix it until it is
|
|
|
|
|
Hello Everyone
I have created a small project in WPF. In this project I have a window with Menu Bar such as:
Administration, Explorers, Reports. Each of these menus have sub menus: for instance under Administration Menu-Bar there is a sub-menu called Users, and under Explorers Menu-Bar there is a sub-menu called Menu Categories.
My problem to my question is that on any of the sub-menus I click, it creates a dynamic tabitem and places them in the main tabcontrol (which this is fine), but if i click again on the same sub menus it repeats the same tabitems.
Can someone please help me solve this problem.
the source code for BackOfficeWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using iPosCloud.com.iposcloud.config.uiC_;
using iPosCloud.com.iposcloud.bo.uiC_.explorer;
using iPosCloud.com.iposcloud.bo.uiC_.explorer.ViewModel;
namespace iPosCloud.com.iposcloud.bo.uiC_
{
public partial class BackOfficeWindow : Window
{
private VMBackOfficeWindow vmBackOfficeWindow;
public BackOfficeWindow()
{
InitializeComponent();
vmBackOfficeWindow = new VMBackOfficeWindow();
this.DataContext = vmBackOfficeWindow;
ObservableCollectionTabItems = new ObservableCollection<VMParentForViews>();
}
public ObservableCollection<VMParentForViews> ObservableCollectionTabItems { get; set; }
private void menuItemAdminConfiguration_Click(object sender, RoutedEventArgs e)
{
RestaurantConfigurationView rcv = new RestaurantConfigurationView();
rcv.ShowDialog();
}
#region "Close TabItems"
private void menuItem1_Click(object sender, RoutedEventArgs e)
{
vmBackOfficeWindow.CloseTabItem(sender);
menuUsers.IsEnabled = true;
menuCategories.IsEnabled = true;
}
#endregion
private void menuUsers_Click(object sender, RoutedEventArgs e)
{
this.vmBackOfficeWindow.AddTab("Users");
menuUsers.IsEnabled = false;
}
private void menuCategories_Click(object sender, RoutedEventArgs e)
{
this.vmBackOfficeWindow.AddTab("Category Explorer");
menuCategories.IsEnabled = false;
}
}
}
and the source code for VMBackOfficeWindow.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Controls;
namespace iPosCloud.com.iposcloud.bo.uiC_.explorer.ViewModel
{
public class VMBackOfficeWindow
{
private VMParentForViews vmParentForViews;
public VMBackOfficeWindow()
{
ObservableCollectionTabItems = new ObservableCollection<VMParentForViews>();
}
public ObservableCollection<VMParentForViews> ObservableCollectionTabItems { get; set; }
public void AddTab(string viewType)
{
if(viewType.Equals("Users"))
{
vmParentForViews = new VMUserExplorer();
this.ObservableCollectionTabItems.Add(vmParentForViews);
}
if(viewType.Equals("Category Explorer"))
{
vmParentForViews = new VMCategoryExplorer();
this.ObservableCollectionTabItems.Add(vmParentForViews);
}
ICollectionView collectionView1 = CollectionViewSource.GetDefaultView(this.ObservableCollectionTabItems);
if (collectionView1 != null)
{
collectionView1.MoveCurrentTo(vmParentForViews);
}
}
#region "Close TabItems"
public void CloseTabItem(Object sender)
{
VMParentForViews vmParentForViews = (sender as MenuItem).DataContext as VMParentForViews;
this.ObservableCollectionTabItems.Remove(vmParentForViews);
}
#endregion
}
}
kind regards
roni
|
|
|
|
|
In the code where you are attempting to add the tab, simply check to see if a tab of this name already exists before you add it.
|
|
|
|
|
Hello Pete
Thanks for replying to my question. According to your answer, there isn't any tab-item with the same name, those tab-items are created at run-time.
here is the xaml code of the BackOfficeWindow.xaml
<Window x:Class="iPosCloud.com.iposcloud.bo.uiC_.BackOfficeWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:iPosCloud"
xmlns:vm="clr-namespace:iPosCloud.com.iposcloud.bo.uiC_.explorer.ViewModel"
xmlns:explorer ="clr-namespace:iPosCloud.com.iposcloud.bo.uiC_.explorer"
Title="CLOUD iPOS - Back Office Window" Height="700" Width="1000" WindowStartupLocation="CenterScreen"
xmlns:Intersoft="http://intersoft.clientui.com/schemas"
xmlns:my1="clr-namespace:Intersoft.Client.UI.Controls;assembly=Intersoft.Client.UI.Controls"
xmlns:my2="http://schehttp://schemas.microsoft.com/surface/2008"
xmlns:my="http://schemas.microsoft.com/surface/2008" Foreground="{x:Null}" ShowInTaskbar="False" WindowStyle="ThreeDBorderWindow">
<Window.Resources>
<DataTemplate DataType="{x:Type vm:VMUserExplorer}">
<explorer:UserExplorer />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:VMCategoryExplorer}">
<explorer:CategoryExplorer />
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.BitmapEffect>
<DropShadowBitmapEffect Color="Black" Direction="360" ShadowDepth="10" Opacity=".5" Softness="9" />
</Grid.BitmapEffect>
<Rectangle>
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.508,1.717" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="1"/>
<GradientStop Color="#FFA3A3A3"/>
<GradientStop Color="#FF3C3C3E" Offset="0.582"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Menu Height="30" HorizontalAlignment="Stretch" Margin="2" VerticalAlignment="Top" Width="Auto">
<MenuItem FontFamily="Verdana" Header="Administration" Padding="7,6,8,3" VerticalContentAlignment="Center" Height="30">
<MenuItem Header="Configuration" Name="menuItemAdminConfiguration" Click="menuItemAdminConfiguration_Click" />
<MenuItem Header="Users" Name="menuUsers" Click="menuUsers_Click" />
</MenuItem>
<MenuItem FontFamily="Verdana" Header="Explorers" Padding="7,6,8,3" VerticalContentAlignment="Center" Height="30">
<MenuItem Header="Menu Categories" Name="menuCategories" Click="menuCategories_Click" />
</MenuItem>
<MenuItem FontFamily="Verdana" Header="Reports" Padding="7,6,8,3" VerticalContentAlignment="Center" Height="30">
</MenuItem>
</Menu>
<Grid Name="Master" Margin="4,40,4,4">
<TabControl Name="MasterTabControl" Margin="2" Background="{x:Null}" BorderThickness="2" BorderBrush="#FF3C3C3E" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding ObservableCollectionTabItems}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" >
<TextBlock.ContextMenu>
<ContextMenu Name="contextMenu1">
<MenuItem Header="Close" Name="menuItem1" Click="menuItem1_Click">
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
</Grid>
</Grid>
<Window.Background>
<ImageBrush ImageSource="/iPosCloud;component/images/HoneyComb.png" Stretch="Fill" TileMode="Tile" Viewport="0,0,46,25" ViewportUnits="Absolute" />
</Window.Background>
</Window>
kin regards
roni
|
|
|
|
|
The tabs are there - all you need to do is search through your ObservableCollection of tabs and see if there's one of the type you want to create. That's what I was alluding to. A naive implementation would be something like this:
if (viewType == "Users")
{
foreach (var tab in ObservableCollectionTabItems)
{
if (tab is VMUserExplorer)
return;
}
} You could simplify this somewhat so that your AddTab and constructor looks like this :
private Dictionary<string, VMParentForViews> viewsDictionary = new Dictionary<string, VMParentForViews>();
public VMBackOfficeWindow()
{
ObservableCollectionTabItems = new ObservableCollection<VMParentForViews>();
viewsDictionary.Add("Users", new VMUserExplorer());
viewsDictionary.Add("Category Explorer", new VMCategoryExplorer());
}
public void AddTab(string viewType)
{
VMParentForViews vm = viewsDictionary[viewType];
Type vmType = vm.GetType();
foreach (var tab in ObservableCollectionTabItems)
{
if (tab.GetType() == vmType)
return;
}
ObservableCollectionTabItems.Add(vm);
} Again, it's still a relatively naive solution, and relies an awful lot on things like string matching and the likes, but it should serve to suffice. If I were doing this, I would go for a much more decoupled approach - you have started some of the way towards this, but there's still a long way to go to get it DI and MVVM.
|
|
|
|
|
Thank you very much Pete that solved my problem...
Once again thank you
kind regards
roni
|
|
|
|
|
Not a problem. Glad I can be of service.
|
|
|
|
|
Hello,
Im already a bit familiar with the MVVM pattern, i still have a few question:
1.When i need Model class in addition to the ViewModel class?
2.If i use the Model class how do i connect the Model and the ViewModel(Binding,events), what is the right way?
3.Where to validate the data in the Model or the ViewModel class?
I know that probabaly there isn't one way to go but what are the rules of thumb?
Thanks.
|
|
|
|