|
I read through that and I just don't understand why I need to implement such a lengthy amount of code for such a simple task. Besides that, the example provided really isn't relevant for what I want. I am looking for a folder browser dialog that returns a directory or even a string if not a directory.
Looking at all this code I see that it is generally a method of reacting to input, but I do not see where it sends information back from the window to the client, aside from giving a dialog response (ok, cancel, etc)
In addition to that, if there is no native folder browser dialog am I going to have to write a user control with a treeview that navigates the file system, because that looks like a lot of excess code as well.
|
|
|
|
|
In my previous response, I gave you an example of why ServiceLocator is "good" as it relates to the folder browser dialog. The link that Abhinav gave you is a bit over engineered and generalized IMO. ServiceLocator is not MVVM. MVVM is the architecture pattern and ServiceLocator is one of the design patterns used to support it. To do MVVM "the right way", you'd need ServiceLocator, a dialog service and an event aggregator service. Some people will use a mediator pattern instead of event aggregator, but I wouldn't. EventAggregator is just as easy (if not easier) to implement and its more loosely coupled and more general.
Once you get past all the pretentious buzz words, all this stuff is pretty basic when implemented in a generic way.
ServiceLocator is just a map of service type -> service instance
EventAggregator is just a map of message type -> subscribers
* unit testability is one reason for MVVM
* expression blend support is another
* you could theoretically have a graphics designer do the eye candy aspect without having to touch the code (theoretically)
* its easier to completely swap views out for something else
Honestly, as I mentioned before, if you don't care about the 4 points above (and don't think that you ever will), why bother with MVVM? it does have an initial startup cost to get everything situated and understand the concepts. BUT, if your infrastructure is well designed in a generic reusable package, that start up cost is one time and can be reused in all future MVVM projects.
Another quick example... if you are used to the Winforms way, your window code are probably very closely coupled to the data structures and control types. If your first pass is a linked list tied to a list control, you probably have all the linked list stuff intermingled with list control stuff. What if you want to change one or both to something else? That'd be a hassle without MVVM, but with MVVM, it would be a lot easier.
|
|
|
|
|
In my many months of research on this I don't think I have found a better explanation than that. I like MVVM and WPF, I like the concepts and the ideas. The esoteric language is what makes it all so difficult. Thanks for the candid response.
|
|
|
|
|
There is a built in FolderBrowserDialog. See SHBrowseForFolder(). Its kind of cheezy looking. If you are only targeting Vista and above, you can use the FOS_PICKFOLDERS flag on IFileDialog for a much nicer one.
|
|
|
|
|
I use WPF with MMVM all the time. I don't understand your confusion. What's wrong with this?
public string PromptForFile()
{
string retVal = string.Empty;
OpenFileDialog fileOpen = new OpenFileDialog
{
InitialDirectory = ".\\",
Filter = "All Files (*.*)|*.*",
FilterIndex = 0,
RestoreDirectory = true
};
if (fileOpen.ShowDialog() == DialogResult.OK)
{
retVal = fileOpen.FileName;
}
return retVal;
}
Place this code in you viewmodel, or in some class called by your view model. Store the return value to a property on the view model that implements INotifyPropertyChanged, and your View will see it automatically.
Everything makes sense in someone's mind
|
|
|
|
|
Kevin, it sounds like you don't really fully understand MVVM. What you did here is "illegal" in MVVM. Your ViewModel is supposed to be unit testable. Popping up a modal dialog violates that.
|
|
|
|
|
umm, ya, sure - I don't understand MVVM.
If you read what I wrote, you would have seen where I said to put this in some class that gets called from the VM.
Everything makes sense in someone's mind
|
|
|
|
|
I did read what you wrote. Did you? Did you read what I wrote?
You gave the OP a PromptForFile method that calls fileOpen.ShowDialog() directly.
It doesn't matter what class that method lives in, calling it from the **VM** is a violation of MVVM -- because it pops up a modal dialog thats not mockable.
Had you used a ServiceLocator like everybody else in this thread suggested, that method would be fine and could even live in your VM.
Are you somehow magically subclassing OpenFileDialog?
MVVM is more then just splitting your CodeBehind into another class. Its also about making your ViewModel unit testable. Popping up a modal dialog (like the OpenFileDialog or MessageBox) without it being replaceable is not allowed.
|
|
|
|
|
The traditional MVVM way to do this would be to implement something like:
public string PromptForFile()
{
IFileDialog dialog = ServiceLocator.Get<IFileDialog>()
{
InitialDirectory = @".\",
Filter = "All Files (*.*)|*.*",
FilterIndex = 0,
RestoreDirectory = true;
}
if (dialog.ShowDialog() == DialogResult.OK)
return dialog.FileName;
return string.Empty;
} Obviously, this implies the use of a service locator, and there are many acceptable alternatives including my particular favourite MEF.
|
|
|
|
|
Am I reading this right?
You're proposing this code is in the View, right?
So you don't really need a ServiceLocator to get you an IFileDialog - you could just use an OpenFileDialog?
What am I missing?
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|
No - I'm proposing it in the VM not the View. This code allows you to test that your logic for loading a file works without having to, either make the file open code public (it should really be private here), or can only be tested from the UI. With the ServiceLocator, you would create a mock IFileDialog that returns you the hardcoded file reference knowing that the UI version will use the version of code you've written that wraps OpenFileDialog. Take a look at the work that Bill Kempf has done on Onyx[^] to see what I mean (and you can see the Silverlight version in there as well that I wrote for Bill).
|
|
|
|
|
Hello to everybody.
I have a grid, which is used to display data (there're about 16 columns and 100 rows) . This way of displaying data was used to make possible cell merging (RowSpan/ColumnSpan) and each cell presents TextBox.
But it's resource-intensive. I would like to use datagrid, but how to make cell merging? Or another control which won't be resource-intensive and will be able to merge.
By the way, I have to create it dynamically.
Best regards.
|
|
|
|
|
I'm styling a treeview so that when the mouse is over a treeviewitem it appears as a gradient bar. I'm trying to get the same effect as the VS2010 menu bars, except in a gold-ish gradient:
<UserControl.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:TreeNode}"
ItemsSource="{Binding Path=Nodes}">
<Border BorderBrush="#E5C365" BorderThickness="1" CornerRadius="5">
<StackPanel Orientation="Horizontal"
Margin="10,0,0,10">
<TextBlock Text="{Binding Path=Caption}" Height="25"></TextBlock>
</StackPanel>
</Border>
</HierarchicalDataTemplate>
<LinearGradientBrush x:Key="TreeItemMouseOverStyle" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#FFFFFF" Offset="0.0" />
<GradientStop Color="#FFF3CF" Offset="0.25" />
<GradientStop Color="#FFECB5" Offset="0.75" />
<GradientStop Color="#FFECB5" Offset="1.0" />
</LinearGradientBrush>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="True" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource TreeItemMouseOverStyle}"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
The problem is, I don't want the border to be visible unless the mouse is over the item. How do I do this?
Everything makes sense in someone's mind
|
|
|
|
|
I would probably try setting a custom style for the Border component - create the new style, set the trigger in the custom style, and set the border's style to the new custom border style.
.45 ACP - because shooting twice is just silly ----- "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001
|
|
|
|
|
Ok, I understand but I'm not quite sure how to. Do you have an example?
Everything makes sense in someone's mind
|
|
|
|
|
Easy.
1) set the initial BorderBrush to Transparent
2) add a MouseOver trigger to the border where you set it to #E5C365
Something like this:
<Border BorderBrush="Silver" BorderThickness="1" Height="43" HorizontalAlignment="Left" Margin="34,202,0,0" Name="border1" VerticalAlignment="Top" Width="99">
<Border.Style>
<Style>
<Style.Triggers>
<Trigger Property="Border.IsMouseOver" Value="True">
<Setter Property="Border.Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
-- Modified Monday, November 15, 2010 3:20 PM
|
|
|
|
|
Well, I thought what you wrote was easy too. Except I coded it and I see no change:
<UserControl.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:TreeNode}"
ItemsSource="{Binding Path=Nodes}">
<Border BorderBrush="Transparent"
BorderThickness="1"
CornerRadius="2">
<Border.Style>
<Style>
<Style.Triggers>
<Trigger Property="Border.IsMouseOver" Value="True">
<Setter Property="Border.BorderBrush" Value="Red" />
<Setter Property="Border.BorderThickness" Value="3" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel Orientation="Horizontal"
Margin="5,2,5,2">
<TextBlock Name="txtProject"
Text="{Binding Path=Caption}"
FontSize="12"
Foreground="#024991">
<TextBlock.ToolTip>
<StackPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Caption}"/>
<TextBlock Text="{Binding Path=FileName}"/>
</StackPanel>
</TextBlock.ToolTip>
</TextBlock>
</StackPanel>
</Border>
</HierarchicalDataTemplate>
<LinearGradientBrush x:Key="TreeItemMouseOverStyle" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#FFFFFF" Offset="0.0" />
<GradientStop Color="#FFF3CF" Offset="0.25" />
<GradientStop Color="#FFECB5" Offset="0.75" />
<GradientStop Color="#FFECB5" Offset="1.0" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="TreeItemSelectedStyle" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#DBEAFC" Offset="0.0" />
<GradientStop Color="#D3E5FC" Offset="0.25" />
<GradientStop Color="#C7DFFC" Offset="0.75" />
<GradientStop Color="#C1DCFC" Offset="1.0" />
</LinearGradientBrush>
<Style x:Name="TreeViewItemStyle" TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="True" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource TreeItemMouseOverStyle}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource TreeItemSelectedStyle}"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
Everything makes sense in someone's mind
|
|
|
|
|
Is the gradient background showing up correctly? Because your style triggers could be breaking the border triggers (not sure on this, you didn't include your code, so its hard to try). If you remove the two triggers from the bottom of the XAML, does the border one work? Because I did try the border one in VS2010 before I posted it . I've seen different levels of triggers interfere with each other. If removing the two bottom triggers fixes the border trigger, then I'd suggest combining those triggers into the data template.
|
|
|
|
|
The mouseover gradient shows up. The selected item gradient does not. Commenting out the triggers didn't do anything. Here's the code again:
<UserControl.Resources>
<!--TreeViewItem Data Template-->
<HierarchicalDataTemplate DataType="{x:Type local:TreeNode}"
ItemsSource="{Binding Path=Nodes}">
<Border BorderBrush="Transparent"
BorderThickness="1"
CornerRadius="2">
<Border.Style>
<Style>
<Style.Triggers>
<Trigger Property="Border.IsMouseOver" Value="True">
<Setter Property="Border.BorderBrush" Value="Red" />
<Setter Property="Border.BorderThickness" Value="3" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel Orientation="Horizontal"
Margin="5,2,5,2">
<TextBlock Name="txtProject"
Text="{Binding Path=Caption}"
FontSize="12"
Foreground="#024991">
<TextBlock.ToolTip>
<StackPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Caption}"/>
<TextBlock Text="{Binding Path=FileName}"/>
</StackPanel>
</TextBlock.ToolTip>
</TextBlock>
</StackPanel>
</Border>
</HierarchicalDataTemplate>
<!--Gradients-->
<LinearGradientBrush x:Key="TreeItemMouseOverStyle" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#FFFFFF" Offset="0.0" />
<GradientStop Color="#FFF3CF" Offset="0.25" />
<GradientStop Color="#FFECB5" Offset="0.75" />
<GradientStop Color="#FFECB5" Offset="1.0" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="TreeItemSelectedStyle" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#DBEAFC" Offset="0.0" />
<GradientStop Color="#D3E5FC" Offset="0.25" />
<GradientStop Color="#C7DFFC" Offset="0.75" />
<GradientStop Color="#C1DCFC" Offset="1.0" />
</LinearGradientBrush>
<!--TreeViewItem Style-->
<Style x:Name="TreeViewItemStyle" TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="True" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource TreeItemMouseOverStyle}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource TreeItemSelectedStyle}"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
Everything makes sense in someone's mind
|
|
|
|
|
Oh... duh... sorry, I didn't read your question closely enough . Two things...
1) your TargetType actually needs to be "{x:Type TreeViewItem}"
2) doing the IsSelected thing will actually be a little tricky... if you examine the stock TreeViewItem template, you'll find a template trigger is doing it:
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
So, unfortunately, that is "overriding" your trigger because the border "Bd" sits on top of the item. What you did works for IsMouseOver (on non selected items) because Bd is transparent in that case and the TreeViewItem background shows through.
You'd need to replace the entire template for TreeViewItem just to get to that sucker
|
|
|
|
|
One other thing... the TreeViewItem template is different for every OS, so you'd need 4 or 5 versions and a custom template selector... pain in the a$$, I know .
|
|
|
|
|
Hi guys
I have a question for you.
I created a c# class on server side, and i want that to be runned when my application starts.Can i do this??(i know that is possibile creating a WCF service)
But i would like to know if there are another way.
Thanks
Bye
|
|
|
|
|
You mean you have a Class and that has a Function and you want to Run the Function when your app starts ?
yes its possible , instatiate your class and create an object as we normally do and call the function. in here
public MainPage()
{
InitializeComponent();
}
Vuyiswa Maseko,
Spoted in Daniweb-- Sorry to rant. I hate websites. They are just wierd. They don't behave like normal code.
C#/VB.NET/ASP.NET/SQL7/2000/2005/2008
http://www.vuyiswamaseko.com
vuyiswa@its.co.za
http://www.itsabacus.co.za/itsabacus/
|
|
|
|
|
Silverlight is a client side technology.
However, you could use the Aspx page host to execute server side code.
The funniest thing about this particular signature is that by the time you realise it doesn't say anything it's too late to stop reading it.
My latest tip/trick
Visit the Hindi forum here.
|
|
|
|
|
Ok.That's right.
So if i create a class at server-side i can't instantiate that at client-side(for ex. in the MainPage's code behind), am i right??
Infact i tried to that but i couldn't.
You said to use the aspx page, i will try this option too.
Are there a tutorial or guide in this forum which explains the differences beetween server and cliend side.What can i do. and what i can't do.
Bye thanks
|
|
|
|