|
Hi there. I'm using WPF and implementing the Model-View-ViewModel pattern. So far, so good.
However, I'm at the point where I want to have the user click a Save button on the view. So I have that Save Click being handled at the ViewModel level. Problem is, it now needs to go through a pre-existing data handling tier. So I can pass the object I have, which is a ViewModel object. But then my data tier has to understand my ViewModel. Or I can split my ViewModel up into discrete data types (int, string, etc.) and pass those through. But I thought I should really have my ViewModel converted back to the Data Model inside the data tier. What's the best approach? I also need to to avoid a circular reference from my main application and my data tier. Help!
Thanks!
|
|
|
|
|
Your model should have no knowledge about your VM. What you need to do is pass the values through to the model from the VM, and you'll update the database from this point. Have a look at my blog entry[^] here to get an idea of what I'm talking about.
|
|
|
|
|
Right. I think the problem that was confusing me is that I have the main ViewModel object (call it PeopleViewModel, if you like) which consists of an ObservableCollection of PersonViewModels as well as a couple of individual PersonViewModel objects of interest. So now I want to save one of these PersonViewModel objects. Where do I convert the PersonViewModel back to a Person? I'm thinking within the PersonViewModel. Then I think you're saying to handle the save at the Person level. Just seems like a lot of things to put my actual data through to get to the save, especially since I then have to go through that pre-existing data handling tier. Am I on the right track, though? Do you know of any code examples? Thanks!
|
|
|
|
|
ml_black wrote: Where do I convert the PersonViewModel back to a Person? I'm thinking within the PersonViewModel.
Correct. In the example link I showed you, the validation in the PersonViewModel is responsible for updating the Person model with the relevant values. What I would tend to do is have a Save command on the View model that called the Save method on your View - yes, it seems like a lot of extra overhead, but it really helps to save your sanity.
Try to think of this as comparable to a n-tiered system, where the UI is the View, the business layer is your ViewModel and the DAL is the model. You wouldn't want the business layer to have to know how to save data to the database, that's the job of the DAL. Similarly, you wouldn't want the DAL to have to be aware of the business rules that surround what is or is not a valid piece of data - that's the job of the BL.
It's this clear separation of concerns that makes MVVM so attractive.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
Thanks, Pete. It became more clear once I actually put it into practice!
|
|
|
|
|
I have a wpf application in which i need to create html document dynamically and when I execute my wpf application i have to display the the htmldocument in internet explorer.
for example,in generally we will create table by using table tag in html.
But i want to create those tags using htmldocument class.
if possible,could you please send me source code
Thanks
Rama Krishna
|
|
|
|
|
A simple search would have found you this[^] page.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
I want to alternate the background color for columns in ListViewItem.
Now my ListViewItem.Template looks like this.
<ControlTemplate TargetType="{x:Type ListViewItem}">
<GridViewRowPresenter Content="{TemplateBinding Content}"
Columns="{TemplateBinding GridView.ColumnCollection}"/>
</ControlTemplate>
Now I can't get each column,cause it is sealed by GridViewRowPresenter and i don't konw how to style the appearence of GridViewRowPresenter.
|
|
|
|
|
Take a look at this - Link[^]
|
|
|
|
|
Thanks a lot ABitSmart.I am such a idiot.Thie problem could be easily sovled and I've spend 12 hours figured it out.
There is a demo in MSDN shows How to:Create ListViewItems With a CheckBox.
Well, we could easily replant it for our problem.
<ListViewItem>
<ListViewItem.Resources>
<DataTemplate x:Key="dt1">
<Border Background="Red">
<TextBlock Text="{Binding col1}"/>
</Border>
</DataTemplate>
<DataTemplate x:Key="dt2">
<Border Background="Yellow">
<TextBlock Text="{Binding col2}"/>
</Border>
</DataTemplate>
</ListViewItem.Resources>
<GridView>
<GridViewColumn CellTemplate="{StaticResource dt1}"
Header="Column1 color red"/>
<GridViewColumn CellTemplate="{StaticResource dt2}"
Header="Column2 color yellow"/>
</GridView>
</ListViewItem>
Very simple!
|
|
|
|
|
That's great. It is what was mentioned in the last reply to the post I shared with you.
Have fun
|
|
|
|
|
Alternatively you can use Ivalue Convertor for doing this
Xaml code:
<Window x:Class="AgeConvertor.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AgeConvertor"
Title="Window2" Height="300" Width="300">
<Window.Resources>
<local:MyConverter x:Key="int2color" />
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding MultipleCountryList}" Height="73" VerticalAlignment="Top">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding CountryName}"
Background="{Binding Converter={StaticResource int2color}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
.CS of Xaml
public partial class Window2 : Window
{
Person p = new Person();
public Window2()
{
InitializeComponent();
this.DataContext = p;
p.LoadCountry();
}
}
ViewModel
public class Person:INotifyPropertyChanged
{
DataSource _objDataSource = new DataSource();
private ObservableCollection<Country> _countrycombo = new ObservableCollection<Country>();
public void LoadCountry()
{
_countrycombo = new ObservableCollection<Country>(_objDataSource.CountryList());
}
public ObservableCollection<Country> MultipleCountryList
{
get
{
return _countrycombo;
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region General Propertychange methods
protected void OnPropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
#endregion
}
ConvertorClass
public class MyConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
int i = ((Country)value).A;
return i % 2 == 0 ? Brushes.Red : Brushes.Green;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
The CountryEntity class
public class Country
{
public string _countryname = string.Empty;
public string CountryName
{
get
{
return _countryname;
}
set
{
_countryname = value;
}
}
}
The Model/DataSource
public class DataSource
{
ObservableCollection<Country> _country = new ObservableCollection<Country>();
public ObservableCollection<Country> CountryList()
{
_country.Clear();
CountryData();
return _country;
}
private void CountryData()
{
_country.Add(new Country {A=1, CountryName = "India" });
_country.Add(new Country { A = 2, CountryName = "USA" });
_country.Add(new Country { A = 3, CountryName = "Canada" });
_country.Add(new Country { A = 4, CountryName = "Singapore" });
}
}
Niladri Biswas
|
|
|
|
|
Great idea! It's much flexible than my way! I'll try it on in the future!
|
|
|
|
|
Niladri Biswas
|
|
|
|
|
Hi,
I'm going to try my best to explain my issue here:
I have a business object called "Task" that consists of TaskName, TaskStart and TaskEnd.
In my UI I have a form that allows a user to enter the above values and a "NewTaskBtn" button to create the Task obj.
Tasks are created at runtime, so each time the "NewTaskBtn" is clicked a couple of things happen
1. a Task Obj is created in the "NewTaskBtn" event handler, using the info supplied above.
2. the Task Obj is also added to a List<Task>
3. At the same time an Expander item is created, with a header consisting of a concatenated string of TaskName + TaskStart + TaskEnd, and a combobox displaying the names of all the tasks in the List<Task>
4. the Expander item is then added to a StackPanel called "TaskSP"
So, at this stage I can create tasks, and have the tasks display in my stackpanel as expanders, containing task info and combobox in the header. right?
Now here is where I hit a brick wall. What I would like to achieve next is,
1. a user should be able to create a couple of tasks, and have the stackpanel fill with epanders containing the task info and comboboxes in the expander headers(this works OK)
2. then the user should be able to select a task in the stackpanel, and using the combobox in the expander header, select another task to add this task to (as a dependancy task, if you catch my drift. in other words adding task a to task b imply's that task a has to be completed before task b can be started)
I would like to use the combobox (in the header of my expander items) selection changed event to do the following:
get the name of the selected task from the combobox, and compare it with the header of the expander items in the stackpanel, and find the matching expander item in the TaskSP. So some sort of linq query that would include a where clause??? this is where I'm completely lost. If I can just get help achieving this, I will be most happy
|
|
|
|
|
I've successfully created a scrolling tab control, and I've figured out how to grab the ScrollViewer control (in the .cs file) that handles scrolling the tabs, but I haven't been able to find a solution to the following issue.
I want the repeat buttons (that the user uses to scroll the tabs) to be enabled/disabled based on the current state of tab control. My goal is to enable/disable the repeat buttons based on several criteria:
0) If there are not enough tabs to require scrolling, both buttons are disabled. Otherwise the buttons are enabled (see next couple of requirements).
1) If the first tab item is in view, the left (prev) button is disabled.
2) If the last tab item is in view, the right (next) button is disabled.
The ScrollViewer wraps a StackPanel . As tabs are added to the TabControl , there is no obvious change to any of the properties that one would expect to indicate that scrolling is required to see additional items. It seems to me that *something* should change somewhere, but I'm not seeing it.
My first attempt at figuring this out included programatically adding tab items and watching the ScrollViewer (and the StackPanel ) under the debugger, and that's when I discovered that none of the obvious values are changing as tabs are added.
It seems to me that this should be able to be handled in the XAML, and I think I would rather do it there, but I am not a WPF "purist", and am more than willing to implement a "code-behind" (god, I hate that term) solution.
I can post code if it's desired, but I didn't want to waste my time or yours with the relatively huge amounts of code that need to be posted for WPF questions. Can anyone help?
---------------
Solved - In the CS file, get the scroller from the tab control, get the buttons from the scroller, and add event handlers to manipulate their enabled status'. If there's a XAML way to do this, I couldn't find it.
"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." - Jason Jystad, 10/26/2001
modified on Monday, June 1, 2009 5:05 PM
|
|
|
|
|
John - have a play round with this on your Repeat button (ensuring that you also set HorizontalScrollBarVisibility="Auto" on the ScrollViewer):
Visibility="{Binding Path=ComputedHorizontalScrollBarVisibility, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
Hmmm. I'll give that a shot. It's not gonna make the scrollbar visible though, is it?
"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." - Jason Jystad, 10/26/2001
|
|
|
|
|
Solved - In the CS file, get the scroller from the tab control, get the buttons from the scroller, and add event handlers to manipulate their enabled status'. If there's a XAML way to do this, I couldn't find it.
Comparing scroller.HorizontalScrollExtent with scroller.ScrollableWidth to see if they're the same.
"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." - Jason Jystad, 10/26/2001
|
|
|
|
|
Hi,
Iam moving my application from MFC to .net wpf . I need to use the bussiness logic dll`s in c++, modifying onli the UI part of it.
I need to get the device context of the control for the same.
Can anyone let me know how to get the device context for a wpf control.
Thanks
|
|
|
|
|
WPF doesn't use device contexts - doesn't really use HWNDs
on the surface either.
WPF is not GDI!
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I was able to get the DC of the window and draw the image in the window loaded event . The thing is the image is not getting retained, its getting redrawn which erases the image again.Any idea like how to overcome this one..
|
|
|
|
|
krishnan.s wrote: Any idea like how to overcome this one..
Yes - Use WPF.
Why use WPF if you're using GDI?
WPF "windows" may be ultimately backed by an HWND, but beyond that everything
is done with a completely different rendering engine.
You should be able to find an equivalent, if not much more robust, way
to do everything in WPF that you are doing with GDI, if you choose to do so.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I'm using BitmapMetadata.GetQuery() to get metadata from JPEG files just fine with queries like the following, for example, to get the creation date: "/app1/ifd/exif/subifd:{uint=36867}". But when I use the same query string with a .TIFF file, I get nothing back. Every query I make on the TIFF file fails.
I know the TIFF file has the metadata in it I'm seeking because I can see it through the Windows Explorer when I hover over the file name. Here is the code I'm using to read the metadata and the debugger shows me that the BitmapSource I get back from the TIFF file has metadata in it, but the GetQuery() returns null. Should the query string somehow be different for the two formats? Any ideas?
BitmapMetadata metaInfo;
Stream imageStream = null;
imageStream = new FileStream(imageUri.LocalPath, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite);
string extension = System.IO.Path.GetExtension(imageUri.LocalPath);
BitmapSource bitmapSource = null;
switch (extension.ToLower())
{
case ".jpg":
JpegBitmapDecoder decoderJpg =
new JpegBitmapDecoder(imageStream,
BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.Default);
bitmapSource = decoderJpg.Frames[0];
break;
case ".tif":
TiffBitmapDecoder decoderTif =
new TiffBitmapDecoder(imageStream,
BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.Default);
bitmapSource = decoderTif.Frames[0];
break;
default:
break;
}
metaInfo = (BitmapMetadata)bitmapSource.Metadata;
if (metaInfo != null)
{
if (metaInfo.ContainsQuery("/app1/ifd/exif/subifd:{uint=36867}"))
return metaInfo.GetQuery("/app1/ifd/exif/subifd:{uint=36867}");
else
return null;
}
else
{
return null;
}
|
|
|
|
|
I'm not sure what the generic queries are for what you're looking for,
but TIFF uses a different format.
Maybe take a look here: Photo Metadata Policy[^]
You can also use TIFF tag values directly if you're familiar with
the format, e.g.
"/ifd/{ushort=256}" Image Width
"/ifd/{ushort=257}" Image Height
"/ifd/{ushort=305}" Software
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|