I am trying to convert my existing program in c# wpf, using mvvm pattern.
The first part is select the Folder location of the files to be process and populate the listbox
I found an example here using Mvvm Light: WPF OpenFileDialog with the MVVM pattern?
the example in the link above is selecting a Folder.
this is the structure of my project
this is the code of my FileListView.xaml
<UserControl x:Class="MvvmLight1.Views.FilesListView"
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:local="clr-namespace:MvvmLight1.Views"
mc:Ignorable="d"
d:DesignHeight="300" Width="730.029">
<Grid>
<ListBox ItemsSource="{Binding FileNames}" Margin="5,5,5,5"/>
</Grid>
</UserControl>
this is my list which reside in ViewModel\OpenFileDialogVM.cs
public System.Collections.ObjectModel.ObservableCollection<string> FileNames { get; }
= new System.Collections.ObjectModel.ObservableCollection<string>();
this is my code for populating the list. but it doesn't work
var files = System.IO.Directory.EnumerateFiles(SelectedPath, "*", System.IO.SearchOption.AllDirectories);
FileNames.Clear();
foreach (var file in files)
{
FileNames.Add(file);
Console.WriteLine(file);
}
What is wrong with my code above?
Code Update:
On my folder structure I have ViewModel Folder and inside it I have OpenFileDialogVm.css
but why is it that the IDE only recognize the ViewModelLocator.
I even Build the project.
I even set the DataContext in the CodeBehind of FileListView user control but still it doesn't populate the listbox
public partial class FilesListView : UserControl
{
public FilesListView()
{
DataContext = new OpenFileDialogVM();
InitializeComponent();
}
}
Add it to your UserControl:
<UserControl
.....
xmlns:viemodels="clr-namespace:MvvmLight1.ViewModels"
/>
<UserControl.DataContext>
<viemodels:OpenFileDialogVM/>
</UserControl.DataContext>
....
</UserControl>
Related
Why can't my custom ListView have it's own xaml file? I have a custom Button and it works with a xaml file with no issues, but not my ListView. The main reason I want to use this approach (rather than be forced to create a Style that is place in the Generic.xaml file) is because I would like to take advantage of the Resources element and place all resources related to the listview within the xaml file:
public sealed partial class MyListView : ListView
{
public MyListView()
{
this.InitializeComponent();
}
}
And here is the associated xaml file:
<ListView
x:Class="App1.MyListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<ListView.Resources>
<!-- I would like to place all related resources here instead of having
them placed in external locations, and then have to open different files to find them. -->
</ListView.Resources>
</ListView>
Although I would expect this should work as well, it seems that this problem is present and it is recommended to use the templated control instead.
I suppose the problem is that assigning the compiler is unable to generate the valid assignment to the Items property of the control, which it is trying to construct from the content of the element. Even when the element is closed immediately it seems to be an issue.
Why not place resources on the Page or inside ListView, rather than deriving your own control?
<Page
x:Class="ListViewResources.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ListViewResources"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<!-- Place all related resources here instead of having them placed in external locations, and then have to open different files to find them. -->
</Page.Resources>
<ListView x:Name="MyListView">
<ListView.Resources>
<!-- Or place related resources here -->
</ListView.Resources>
</ListView>
</Page>
I have a WPF window containing a ListBox. The ItemsSource is bound to a property of a view model.
<Window x:Class="SimpleWpfApp.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding MainWindowViewModel, Source={StaticResource Locator}}">
<DockPanel>
<ListBox ItemsSource="{Binding SomeThings}" />
</DockPanel>
</Window>
The property of the view model is an observable collection of a custom interface; ISomeInterface. The interface is very simple and is implemented by SomeClass which additionally overrides ToString.
public class MainWindowViewModel
{
public ObservableCollection<ISomeInterface> SomeThings
{
get
{
var list = new List<ISomeInterface>
{
new SomeClass {Value = "initialised"},
new SomeClass {Value = "in"},
new SomeClass {Value = "code"}
};
return new ObservableCollection<ISomeInterface>(list);
}
}
}
public interface ISomeInterface
{
string Value { get; }
}
public class SomeClass : ISomeInterface
{
public string Value { get; set; }
public override string ToString() => Value;
}
When I view the window in Visual Studio 2015 or Blend all is as expected. ToString is called and the ListBox populated.
Blend screenshot
I have created XAML design data which I want to use when in design mode. I have added the design data in a directory called SampleData. I add a design datacontext statement to the window XAML immediately below the first DataContext.
d:DataContext="{d:DesignData Source=/SampleData/Data.xaml}"
This doesn't work. Visual Studio and Blend report 'File or project item not found' regardless of what I use for source path. I have tried /SampleData/Data.xaml, SampleData/Data.xaml, ../SampleData/Data.xaml, ./../SampleData/Data.xaml
Visual Studio and Blend only find Data.xaml if I move it out of the SampleData directory and into the project root. Then I am able to reference it using source path /Data.xaml or Data.xaml. If I use Data.xaml without prefixing / then Visual Studio and Blend report that the file cannot be found.. but find it anyway.
My first question is .. Can I use sample data in a sub-directory? And if so how?
Having successfully referenced Data.xaml in the project root, my window is not calling the overridden ToString so I'm getting a list of class name displayed. The list has the same number of items as the design data so it appears it is using the design data.
My second question is .. Why is the overridden ToString not being called here when it is if the objects are instantiated from code?
I'm aware I can achieve the desired result by specifying an item template.
<ListBox ItemsSource="{Binding SomeThings}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Full source is available for the example application on github
https://github.com/DangerousDarlow/WpfDesignData
UPDATE
Thanks to jstreet for answering. I changed the file properties for data.xaml in the sub directory and am now able to use this as design data. I thought I'd tried this before but I must be mistaken.
I'm still not seeing ToString being called. I tried changing the view model property to List<object> and also List<ISomeInterface> but both resulted in called to object.ToString; deduced by the display of the class name. I'll probably stop looking at this point as I'm not going to be using ToString anyway, I'll bind to the properties I want to display. It would be good to explain the difference in behaviour though.
I'm using Visual Studio 2015 community edition.
Here's some working sample code. You may want to refer to This article - MSDN.
In particular, note how to set properties for your Data.xaml file (Dictionary1.xaml, in my case) in your VS project:
Also note how to create your root object, SomeThings (SomeClasses in my case):
For collections, the root object can be an ArrayList or a custom type that derives from a collection or generic collection...
XAML:
<Window x:Class="WpfApplication277.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication277"
d:DataContext="{d:DesignData Source=/SampleData/Dictionary1.xaml}"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListView ItemsSource="{Binding}"></ListView>
</Grid>
Dictionary1.xaml:
Right-click SampleData folder in your VS project, and select Add\New Item\WPF\Resource Dictionary, replace its contents with your design data. This should make sure your design data can be located in a sub-folder.
<m:SomeClasses xmlns:m="clr-namespace:WpfApplication277">
<m:SomeClass Value="design data 1">
</m:SomeClass>
<m:SomeClass Value="design data 2">
</m:SomeClass>
<m:SomeClass Value="design data 3">
</m:SomeClass>
SomeClasses: List<SomeClass> did NOT work !
public class SomeClasses : List<Object>
{
public SomeClasses() { }
}
SomeClass:
public class SomeClass : ISomeInterface
{
public string Value { get; set; }
public override string ToString() => string.Format("ToString() : {0}",Value);
}
Note that ToString() is definitely being called:
Hello I am using Prism in my demo project and I have a problem with user controls' inheritance. If I use my user control base class for my user control like below, user control's content is showing up empty. Then when I use
<igf:UserControlBase x:Class="DemoProject.Views.DemoView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:igf="http://igf.schema"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="200">
<StackPanel>
<TextBox Text="Hello Prism"/>
<TextBlock Text="Hello Prism"></TextBlock>
</StackPanel>
</igf:ViewControlBase>
and this is my user control and it is in another project. And ctors are commented now but still not working. Only way is changing
using System.Windows;
using System.Windows.Controls;
namespace DemoProject.Base.Controls
{
public class UserControlBase : UserControl
{
static UserControlBase()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(UserControlBase), new FrameworkPropertyMetadata(typeof(UserControlBase)));
}
public UserControlBase()
{
DefaultStyleKey = typeof(UserControlBase);
}
}
}
I found solution by adding code below into Assembly.cs file to user control's project
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
I'm developing a Windows 8.1 Store app with C# and .Net Framework 4.5.1.
I'm trying to bind Password.SecurePassword to a ViewModel, and reading this SO answer I found a way to do it: Put the PasswordBox in my ViewModel.
But I don't know how to do it. I know how to bind Dependency Properties, but I don't know how to put that control on my ViewModel. This is my XAML:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
DataContext="{Binding MainViewModel, Source={StaticResource Locator}}"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<PasswordBox x:Name="userPassword" />
</Grid>
</Page>
What do I have to do?
You have several options but I'll just give you the basic option without third party libraries.
In your Page constructor. You can do something like this.
public Page()
{
var mainViewModel = this.DataContext as MainViewModel;
if(mainViewModel != null)
{
mainViewModel.PasswordBox = userPassword;
}
}
You can also set it on the Loaded event of the View and set the PasswordBox to the ViewModel.
does anyone have an example or tutorial on how to use Caliburn Micro together with ModernUi (https://mui.codeplex.com)?
Ok so I had a quick mess about with it and a look on the Mui forums and this seems to be the best approach:
Since the window loads content from URLs you need to take a view-first approach, and then locate the appropriate VM and bind the two.
The best way to do this appears to be via the ContentLoader class which is used to load the content into the ModernWindow when it is requested. You can just subclass DefaultContentLoader and provide the necessary CM magic to bind up loaded items:
public class ModernContentLoader : DefaultContentLoader
{
protected override object LoadContent(Uri uri)
{
var content = base.LoadContent(uri);
if (content == null)
return null;
// Locate the right viewmodel for this view
var vm = Caliburn.Micro.ViewModelLocator.LocateForView(content);
if (vm == null)
return content;
// Bind it up with CM magic
if (content is DependencyObject)
{
Caliburn.Micro.ViewModelBinder.Bind(vm, content as DependencyObject, null);
}
return content;
}
}
Your CM bootstrapper should just bootstrap a ModernWindow viewmodel which is backed by a ModernWindow based view (CM tries to use EnsureWindow which creates a new basic WPF Window class, unless of course your control already inherits from Window which ModernWindow does. If you need all dialogs and popups to be MUI you might need to reimplement WindowManager):
public class Bootstrapper : Bootstrapper<ModernWindowViewModel>
{
}
Which can be a conductor (OneActive) and looks like this:
public class ModernWindowViewModel : Conductor<IScreen>.Collection.OneActive
{
}
And XAML for the view is
ModernWindowView.xaml
<mui:ModernWindow x:Class="WpfApplication4.ViewModels.ModernWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mui="http://firstfloorsoftware.com/ModernUI"
Title="ModernWindowView" Height="300" Width="300" ContentLoader="{StaticResource ModernContentLoader}">
<mui:ModernWindow.MenuLinkGroups>
<mui:LinkGroupCollection>
<mui:LinkGroup GroupName="Hello" DisplayName="Hello">
<mui:LinkGroup.Links>
<mui:Link Source="/ViewModels/ChildView.xaml" DisplayName="Click me"></mui:Link>
</mui:LinkGroup.Links>
</mui:LinkGroup>
</mui:LinkGroupCollection>
</mui:ModernWindow.MenuLinkGroups>
</mui:ModernWindow>
Obviously you need to make the loader a resource too:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.xaml" />
<ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.Dark.xaml"/>
<ResourceDictionary>
<framework:ModernContentLoader x:Key="ModernContentLoader"></framework:ModernContentLoader>
<wpfApplication4:Bootstrapper x:Key="Bootstrapper"></wpfApplication4:Bootstrapper>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Here's the ChildViewModel I'm using as a test:
public class ChildViewModel : Conductor<IScreen>
{
public void ClickMe()
{
MessageBox.Show("Hello");
}
}
And the XAML for that (just a button)
<UserControl x:Class="WpfApplication4.ViewModels.ChildView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350" Width="525">
<Grid>
<StackPanel>
<TextBlock >Hello World</TextBlock>
<Button x:Name="ClickMe" Width="140" Height="50">Hello World</Button>
</StackPanel>
</Grid>
</UserControl>
And the proof of concept:
I create a very, very simple sample of chat app using Modern UI for WPF, Caliburn Micro and MEF.
https://github.com/gblmarquez/mui-sample-chat
I hope it helps