Binding app.xaml to view WPF in c# - c#

I use MVVM framework and got this tutorial on net: https://code.msdn.microsoft.com/windowsdesktop/How-to-use-MVVM-Pattern-0e2f4571 and http://www.c-sharpcorner.com/UploadFile/raj1979/simple-mvvm-pattern-in-wpf/
Now, my problem is:
I can't display the mainpage.xaml even there is no semantic error. Here's my code on app.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BasicWPF.View.MainPage window = new MainPage();
UserViewModel VM = new UserViewModel();
window.DataContext = VM;
window.Show();
}
Can anyone help me? Thanks for any help! :)
Thanks to everyone who helped.
[SOLVED]
Change the startupuri in app.xaml to where the page you want to load. In my case
1: I change it:
StartupUri="View/MainPage.xaml"
2: In app.xaml.cs, I typed in this code:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BasicWPF.View.MainPage window = new MainPage();
UserViewModel VM = new UserViewModel();
window.DataContext = VM;
}
from my previous code, delete this code: window.show(); because it startup the page twice coming from app.xaml and app.xaml.cs. To prevent that, delete: window.show();
Thank you again! :)

Set the starting page in app.xaml, not the app.xaml.cs file - in the Application tag, if there is no property StartupUri - add one and set its value to your page name, this way the page will be automatically shown as soon as your application is started. It should look something like this:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainPage.xaml">
I am considering that you are doing it this way because you wish to set the DataContext of the page, but there is a better way to set the DataContext of your page and it is by setting it directly into your XAML code. Here is an example:
<Page x:Class="WpfApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525" >
<Page.DataContext>
<local:UserViewModel/>
</Page.DataContext>
xmlns:local is a prefix mapping to the namespace you have set for it. Having this you are able to access the types contained in the namespace using the prefix - local:UserViewModel.

what you can do is instead of setting data context in app.xaml.cs, just hook up the loaded event of main window and add the following code.
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
UserViewModel VM = new UserViewModel();
this.DataContext = VM;
}
This should work. Dont forget to remove the codes from App.xaml.cs.
Thanks

SO in your case you have a main window inside that main window you need to load the page.
What you can do is add a frame to your mainwindow like
<Frame x:Name="myFrame"/>
then inside the mainwindow loaded event add the below code
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
UserViewModel VM = new UserViewModel();
this.DataContext = VM;
myFrame.Content = new MainPage();
}
This is like we are adding a frame and loading your view to that frame.

Related

Use ChromiumFX/ChromiumWebBrowser inside an C# addin

I’m trying to add a ChromiumWebBrowser components inside a C#/WPF addin. (Before the addin used CefSharp but the new version of the host application run addin inside custom AppDomain so CefSharp doesn’t work anymore.)
To the problem is, when I call ChromiumWebBrowser.Initialize() a new instance of the host application is launch 🤔 (with some command line args which are dropped by the application).
I really don’t understand the stuff around this command line.
Can you explain to me where I do a mistake ? ChromiumWebBrowser cannot be used inside addin ? I miss somethings ?
Here the C# sample of my code
public partial class myWindow : Window
{
public myWindow()
{
CfxRuntime.LibCefDirPath = #"E:\sources\app\Output\Debug_msvc2017_x64\Addins\cef\Release64";
ChromiumWebBrowser.OnBeforeCfxInitialize += ChromiumWebBrowser_OnBeforeCfxInitialize;
ChromiumWebBrowser.OnBeforeCommandLineProcessing += ChromiumWebBrowser_OnBeforeCommandLineProcessing;
Chromium.WebBrowser.ChromiumWebBrowser.Initialize();
InitializeComponent();
// browser is a ChromiumWebBrowser instance
browser.MouseClick += Wb_MouseClick;
browser.Show();
}
private void Wb_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
(sender as ChromiumWebBrowser).LoadUrl("https://www.google.com"); // properly trigger but nothings will be displayed
}
static void ChromiumWebBrowser_OnBeforeCommandLineProcessing(CfxOnBeforeCommandLineProcessingEventArgs e)
{
Console.WriteLine(e.CommandLine.CommandLineString); // here the command line create a new instance of the application where the plugin is loaded
}
static void ChromiumWebBrowser_OnBeforeCfxInitialize(OnBeforeCfxInitializeEventArgs e)
{
e.Settings.LocalesDirPath = #"E:\sources\app\Output\Debug_msvc2017_x64\Addins\cef\locales";
e.Settings.ResourcesDirPath = #"E:\sources\app\Output\Debug_msvc2017_x64\Addins\cef\Resources";
}
}
‌
And the xaml part
‌
<Window x:Class="App.Views.myWindow"
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:App.Views"
xmlns:webbrowser="clr-namespace:Chromium.WebBrowser;assembly=ChromiumWebBrowser"
mc:Ignorable="d"
Title="myWindow" Height="800" Width="1200">
<Grid x:Name="grid1">
<WindowsFormsHost x:Name="wpfContainer">
<webbrowser:ChromiumWebBrowser x:Name="browser"></webbrowser:ChromiumWebBrowser>
</WindowsFormsHost>
</Grid>
</Window>
‌
Thanks in advance for your help ;)

Drawing image into a Window and update it

I have an unsafe class that generate a Bitmap which is converted to ToImageSource in order to draw into a Window. The Bitmap itself contains a sinusoidal text which is frequently updated and I want to it "move" from the left to the right (marquee style?). Anyway it works just fine in a WinForm but I'm stuck with the WPF Window.
Here are some code samples:
public AboutWindow()
{
InheritanceBehavior = InheritanceBehavior.SkipAllNow;
InitializeComponent();
Initialize();
}
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
drawingContext.DrawImage(bitmapRender.WindowBitmap, drawingArea);
if (!worker.IsBusy)
worker.RunWorkerAsync(); // BackgroundWorker in charge of updating the bitmap
}
void DispatcherTimerRender_Tick(object sender, EventArgs e) => InvalidateVisual();
My issues are: there is nothing displayed on the Window and the DispatchedTimer that calls InvalidateVisual() leads to this exception:
System.InvalidOperationException: 'Cannot use a DependencyObject that belongs to a different thread than its parent Freezable.'
I have looked at other threads and I'm aware that WPF is a retained drawing system but I would love to achieve it anyway.
Any suggestion about the "best" way to achieve this?
Any useful explanation/link would be very much appreciated.
[Edit]
<Window x:Class="CustomerManagement.View.AboutWindow"
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" Height="450" WindowStartupLocation="CenterScreen" Width="800" ResizeMode="NoResize" AllowsTransparency="True" WindowStyle="None">
<Grid KeyDown="Grid_KeyDown">
<Image Width="800" Height="450" Source="{Binding 'Image'}" />
</Grid>
</Window>
You should use an Image element that has its Source property bound to an ImageSource property in a view model. This is the "standard" way, based on the MVVM architectural pattern, and therefore the "best" way - in my opinion.
<Image Source="{Binding Image}"/>
The view model could look like this:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ImageSource image;
public ImageSource Image
{
get { return image; }
set
{
image = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Image)));
}
}
}
and an instance of it would be assigned to the DataContext of the window:
public AboutWindow()
{
InitializeComponent();
var vm = new ViewModel();
DataContext = vm;
}
For testing it, the code below performs a slide show of image files in a directory. You may as well assign any other ImageSource - e.g. a DrawingImage - to the Image property.
var imageFiles = Directory.GetFiles(..., "*.jpg");
var index = -1;
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
timer.Tick += (s, e) =>
{
if (++index < imageFiles.Length)
{
vm.Image = new BitmapImage(new Uri(imageFiles[index]));
}
else
{
timer.Stop();
}
};
timer.Start();

WPF: Popout existing usercontrol

Imagine next situation: I do have application window with several usercontrols inside. They was displayed side by side in past, but now I want to show one of them in popup window. Not in Popup control but new Window.
See example XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication3="clr-namespace:WpfApplication3"
Title="MainWindow"
Height="350"
Width="525">
<Grid>
<wpfApplication3:UserControl1 Visibility="Hidden"
x:Name="UserControl1"/>
<Button Click="ButtonBase_OnClick"
Width="100"
Height="60">open window</Button>
</Grid>
In code behind I need to deattach usercontrol from current Window and assign to new one:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var parent = VisualTreeHelper.GetParent(UserControl1);
if (parent != null)
{
parent.RemoveChild(UserControl1);
}
var w = new Window
{
Content = UserControl1,
Title = "sample",
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.CanResize
};
w.Show();
}
And after calling w.Show() I always getting blank white window.
If in button click handler change
Content = UserControl1
to
Content = new UserControl1()
I will get right content as well.
But I can't use this way because I want to keep my usercontrol state during pop-out and pop-in events.
So how can I show in new window existing usercontrol without recreating it?
I am not sure how you are calling RemoveChild on a DependencyObject as that method doesn't seem to exist. Note that VisualTreeHelper.GetParent returns a DependencyObject so, the code you posted should not compile unless you have an Extension method somewhere defining RemoveChild.
In your case what you want to do is cast your parent object to type Grid or Panel and then remove the UserControl from the Children property, then set your UserControl as the Content of your window.
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Grid parent = VisualTreeHelper.GetParent(UserControl1) as Grid;
if (parent != null)
{
parent.Children.Remove(UserControl1);
}
var w = new Window
{
Content = UserControl1,
Title = "sample",
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.CanResize
};
w.Show();
}
There was a similar question asked here
that gives a very detailed answer.
The quick answer is that you will have to remove the control from the main window and then add it to the popup window.

How to use Application.Exit Event in WPF?

I need to delete some certain files, then user closes program in WPF. So I tried MDSN code from here http://msdn.microsoft.com/en-us/library/system.windows.application.exit.aspx this way:
this code located here App.xml.cs
public partial class App : Application
{
void App_Exit(object sender, ExitEventArgs e)
{
MessageBox.Show("File deleted");
var systemPath = System.Environment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
var _directoryName1 = Path.Combine(systemPath, "RadiolocationQ");
var temp_file = Path.Combine(_directoryName1, "temp.ini");
if (File.Exists(temp1_file))
{
File.Delete(temp1_file);
}
}
}
// App.xaml
<Application x:Class="ModernUIApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
ShutdownMode="OnExplicitShutdown"
Exit="App_Exit">
<Application.Resources>
First of all it doesn't delete files, secondly this program stays in the process after I pushed exit button( this is really strange). This code don't give any errors. And finally it doesn't show MessageBox So anything wrong here?
I think he just can`t find this function.
It's quite simple:
Add "Exit" property to the application tag
<Application x:Class="WpfApplication4.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
Exit="Application_Exit">
</Application>
and handle it in the "code behind"
private void Application_Exit(object sender, ExitEventArgs e)
{
// Perform tasks at application exit
}
The Exit event is fired when the application is shutting down or the Windows session is ending. It is fired after the SessionEnding event. You cannot cancel the Exit event.
you should add app_exit in your xaml code
<Application x:Class="CSharp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
ShutdownMode="OnExplicitShutdown"
Exit="App_Exit"
>
</Application>
you can just hook the event Closing on your main window like this -
<Window Closing="Window_Closing">
And in your event do all the work you need
private void Window_Closing(object sender, CancelEventArgs e)
{
MessageBox.Show("File deleted");
var systemPath = System.Environment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
var _directoryName1 = Path.Combine(systemPath, "RadiolocationQ");
var temp_file = Path.Combine(_directoryName1, "temp.ini");
if (File.Exists(temp1_file))
{
File.Delete(temp1_file);
}
}
If you don't like adding Exit event to XAML, you could try this alternative.
Add following method to your App.xaml.cs:
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
// Your code here
}
If you want to follow MVVM principle you can use System.Windows.Interactivity.WPF.
MainWindow.xaml
<Window x:Class="Endonext.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:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding WindowClosingCommand, Mode=OneTime}" />
</i:EventTrigger>
</i:Interaction.Triggers>
MainWindowViewModel.cs
public class MainWindowViewModel
{
ICommand WindowClosingCommand => new RelayCommand(arg => this.WindowClosing());
private void WindowClosing()
{
// do what you want.
}
}
This approach is more testable.
Have a nice day.
Make sure that the namespace (MyApp) matches "x:Class=MyApp..."
Under properties for <Application></Application>, double click on the textbox next to 'Exit'.
If you get "Unable to add event handler" then Rebuilding the project fixed it for me.
XAML
<Application x:Class="MyApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
Exit="Application_Exit"
>
Code behind
using System.Windows;
namespace MyApp
{
public partial class App : Application
{
private void Application_Exit(object sender, ExitEventArgs e)
{
//your code
}
}
}

Assign tab content in WPF to a page

I am trying to add dynamic tabs to my application. Right now if I click a button, it will open a new page. What I want is to open this page in a new tab. But when I set up the tab content to a page , the code complains. I wanna do something like this
private void bttnGoToClientsOnClick(object sender, RoutedEventArgs e)
{
var content = new TextBlock();
TabItem tab = new TabItem();
tab.Header = "Search Page";
SearchPage sp = new SearchPage();
tab.Content = sp;
tabControl.Items.Add(tab);
this.NavigationService.Navigate(sp);
}
is there any way I can convert my page to usercontrol or cast it as user control
Thank you!
But when I set up the tab content to a page , the code complains.
It wouldn't hurt if you were more specific here :)
What is SearchPage class? It doesn't seem to be the part of the WPF framework. I googled it up on the
http://www.intersoftpt.com/ website. Is that it?
TabItem.Content needs to be of ContentControl type, which SearchPage - apparently - is not. I'm sure you need to embed this SearchPage object in some control presenter, such as a panel, before you can assign it to TabItem.Content.
Update:
Try this, then:
TabItem tab = new TabItem();
tab.Header = "Search Page";
SearchPage sp = new SearchPage();
this.NavigationService.Navigate(sp);
// ----------------------------------------------------
var frame = new Frame(); // !
frame.Navigate(sp); // !
tab.Content = frame; // !
// ----------------------------------------------------
tabControl.Items.Add(tab);
While I believe this should work, I haven't tested it. Please let me know if it doesn't do the trick.
You can always create your own UserControls, directly in the XAML definition (even if they are partial pages or windows).
In this example I assume that your SearchClass is defined in the [YourProject].Model namespace (where [YourProject] is the name of your project)
<UserControl x:Class="WpfApplication1.UserControl1"
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:search="clr-namespace:[YourProject].Model">
<search:SearchClass>
<!--<Grid>
...ANYTHING YOU WANT HERE ! ...
</Grid>-->
</search:SearchClass>
</UserControl>
Now you can create an instance of the UserControl, even in XAML or in code-behind (remember only to declare the namespaces correctly!):
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:ctrls="clr-namespace:WpfApplication1"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<UserControl1 />
</Grid>
</Window>
...and this my code-behind...
UserControl1 myControl = new UserControl1();

Categories

Resources