|
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.
|
|
|
|
|
You *always* have a View, VM and Model. None of the parts are optional.
View - Strictly 100% XAML (in fact, I prefer to delete the code behind entirely to prevent lazy programmers from uglifying the code). Some people will argue this is not a requirement, but IMO, it should be, it keeps the code cleaner. If you need to do something "complex" with a control, it shouldn't be done in the code behind, but rather broken out into a reusable UserControl.
ViewModel - View binds to this class. Someone will now argue: but how do I set the VM since you have deleted the code behind? -- Answer: ViewLocator & DI. DI plays a second part in this class. It is used to inject the model into the constructor. ViewModel just wraps the Model with lazy load style properties and exposes commands that operate on the model, etc.
Model - This is the API / storage layer of your objects. I like to break this out into its own assembly that a single programmer is managing for consistency. This is the *only* assembly that should even know what a database is. No database / persistence code of any kind is allowed anywhere else in the project. I like breaking the model out into its own assembly to keep things clean and in one place. Model should implement INPC and INCC.
|
|
|
|
|
Collin Jasnoch wrote: 10 min ago
Nice. I usually find the answer about 10 seconds after I click "Submit" on my question
|
|
|
|
|
I have a Silverlight app that displays a map with Deep Zoom. Having just updated the map image, I uploaded the new image files and XAP to our server and even though the XAP refreshes in the browser to the new version (I'm using versioning specifically to force the XAP refresh and that part works fine), the image files for the map, which are stored on the server in the ClientBin, are NOT refreshing automatically in the browser. I eventually got them to refresh for me after failed attempts at refreshing the browser screen, clearing the browser cache (Firefox and IE), and eventually I went into the Windows Control Panel, chose Internet options, and cleared the temporary Internet files from there and only THEN did the map images refresh and I could view the updated map image in my Silverlight app. Did not have to go through all of this with the local development server in VS of course.
So what can I do to force a refresh for everyone who accesses my ASP.NET page with my Silverlight Deep Zoom map on it so that they can see the updated map image and not the old image files being stored locally in their temporary Internet files cache?
Thanks in advance...
--Will
|
|
|
|
|
I've dealt with the caching of the SL xaps before, especially in IE, and there is a technique there that works well to avoid that problem. I'm not sure if it will address your issue but it should be pretty easy to test.
The problem is that even if you set a content expiration policy on your resources, IE ignores it. You can see this by running your app with Fiddler running in the background. You will probably see 304 requests for your images which means IE is asking if it needs to update the image.
The key is the URL. IE determines if it should request a resource or ask if it should be refreshed based on the URL. To IE, your image request looks like http://myserver/foo.jpg every time the image is called. IE will look in the cache and make a content refresh request to the server. If the name is the same, you get the cached version. Same things happens for XAPs which is what was bothering me.
The fix is to pass a bogus parameter in the URL. So change the image request to http://myserver/foo.jpg?bogus=1. The parameter name and number can be anything. Each time you need to force a download of the image, just change the number. This will create a new, unique URL as far as the browser is concerned and new URLs are never checked against the cache. This should be easy to test by adding the parameter to the web request and then incrementing it while watching what happens in Fiddler.
If you always update the images in lock-step with the xap, you could just pass an assembly version number as the parameter. Another possibility (and the one I use) is to patch the hosting page with a bit of PHP that allows your application to get the date & time on the image file and pass that as the parameter. The nice thing here is that as soon as the image is updated on the server, the result of that call will change and the resulting URL will change. Since you are calling inside your app, you would probably need a web service or something that would allow you to do that before calling for the image appending the date/time to the web request.
While these links apply to xaps, the same should work for the image files as well. Here is one for configing the expiration policy on IIS:
http://mattduffield.wordpress.com/2011/08/26/having-problems-with-iis-caching-your-silverlight-application/[^]
Here is the date/time trick embedded in the web page:
http://codeblog.larsholm.net/2010/02/avoid-incorrect-caching-of-silverlight-xap-file/[^]
And finally, here is a guy that refined the previous post:
http://derreckdean.wordpress.com/2012/03/14/ie9-and-silverlight-caching-problems/[^]
HTH!
|
|
|
|
|
Hi Jason, thank you so much for the reply!
Question: can I do something as simple as changing the name of the folder on the server that the images are stored in (and changing it in the new XAP as well so it's looking in the new location) in order to duplicate this fix? In other words, if I have my images in a subfolder of the ClientBin called "images", can I just rename that subfolder to "imagesblahblah" in order to dupe IE, etc, into downloading the new versions? Thanks!
|
|
|
|
|
If the folder is part of the URL then yes... that would work as well. Any part of the URL changing will trick the browser into thinking it is a new URL. The dummy parameter is just a technique to force the refresh without rearranging your deployment. If you are OK with publishing a new xap that contains a new folder path each time, then it should work just as well.
|
|
|
|
|
I just tried it and it works--thank you so much!!!
|
|
|
|
|
Good to hear. Glad I could help.
For anyone else that may come across this issue, this is a problem with any resource retrieved via a web request in Silverlight. Because SL runs in the browser, web requests go through the browser's URL handling mechanism. So any static resource you fetch from SL could potentially get cached like this.
I haven't tried it with OOB SL apps but I suspect the problem would exist there as well. If someone has tried it, please chime in!
|
|
|
|
|
Not finding any good explanations so far... trying to figure out CompositeCommands & IActiveAware. I understand that the CompositeCommand is a static "shell" command and as part of your VM init, you attach the "local" command to the "shell" command via RegisterCommand(). That part makes sense.
The part that doesn't is IActiveAware.
From the source code for CompositeCommand, it seems like the "local" Command is supposed to implement IActiveAware. However, if I have 100 commands, I would need to implement it 100 times. Google searches seem to mention that only the VM is supposed to implement IActiveAware and something about the region manager???
How does the region manager tie in the IActiveAware on the VM into a non existant one on the "local" ICommand? How does the IsActive get set on the commands "automagically"?
|
|
|
|
|
I am developing a MVVM application using C#. I have a property called 'ReportedDate' of type DateTime which is optional in database field. In my view I have bound 'ReportedDate' property to txtReportedDate text box.
After getting data from database, if there is no value in ReportedDate field, I want to display blank in txtReportedDate text box. But empty values cannot be assign to the property 'ReportedDate' in ViewModel. It gives errors.
How can I do this?
|
|
|
|
|
By itself, a DateTime cannot be null. To make it a nullable type, use DateTime?
|
|
|
|
|
Could you please give an example?
|
|
|
|
|
I already showed you. The question mark after the type made it nullable.
|
|
|
|
|
You might need a value converter as well to box and unbox the nullable DateTime. The framework will not directly cast DateTime? to DateTime.
|
|
|
|
|
Could you please give an example?
|
|
|
|
|
why not choosing a nullable type or making a valueConvert when binding
|
|
|
|
|
I have a main window (ribbon). The ribbon has 2 buttons. Call them BtnA and BtnB. The view area is a tab control. Tab1 and Tab2. Each has a user control. UserCtrl1 and UserCtrl2. So BtnA should execute Cmd1 in UserCtrl1 and BtnB should execute Cmd2 in UserCtrl2.
So the question is, what is the cool MVVM way to set that up? The main window doesn't have the data context for the user controls, so it can't do straight up binding. I could have Cmd1 and Cmd2 be static commands, but then you end up with 2 sets of functions... a static Execute & a class Execute, a static CanExecute and a class CanExecute. Not good. Could also have forwarding functions in the main window, but thats pretty much the same issue. 2 sets of functions.
|
|
|
|
|
Effectively, you can tackle this using a Mediator or Messenger. The buttons trigger messages that the tab view models hook up to. The beauty of this is that the whole implementation is nicely decoupled.
|
|
|
|
|
Yeah, thats even messier. Gotta sub to msgs, create a payload class, etc.
Was reading about composite commands. That seems to be a pretty slick solution. Still requires the 2 command solution, but its a bit more generic on the forwarding logic and has the built in switch to handle IActiveAware.
Playing around with them now.
|
|
|
|
|
A neat way to address this problem is to divide your screen into logical groups called Regions.
This is typically done via using Prism.
Once you have your regions defined, you can plug views in and out of the regions on demand.
Prism works well with MVVM and Silverlight.
|
|
|
|