Bing WPF adding labels to pushpins - c#

I'm trying to add labels to my Pushpins, and I'm experimenting with two different ways to add the pushpin to the map.
Test 1 is from the xaml code, I can add the pushpin but I can't figure out how to add text
Test 2 is from the C# code, when I try to open the map I get an error of "Object refernce not set to an instance of an object on the line "myMap.Children.Add(pin);"
XAML code:
<Window x:Class="WPFKiosk.MapWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:Microsoft.Maps.MapControl.WPF;assembly=Microsoft.Maps.MapControl.WPF"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFKiosk"
mc:Ignorable="d"
Title="MapWindow" Height="910" Width="1080" WindowStyle="None" ResizeMode="NoResize">
<!-- -->
<Window.Resources>
<ControlTemplate x:Key="PushpinControlTemplate" TargetType="m:Pushpin">
<Image x:Name="pinImage" Height="64" Source="/Images/Push_Pin.png"/>
</ControlTemplate>
</Window.Resources>
<Grid Width="1080" Height="915">
<m:Map x:Name="myMap" CredentialsProvider="My_Key" Mode="Road">
<m:Pushpin Location="28,-81"/>
<!-- Test 1 -->
</m:Map>
<Image HorizontalAlignment="Left" Height="100" Margin="510,740,0,0" VerticalAlignment="Top" Width="100" Source="Images/iTO Back Arrow.png" MouseLeftButtonDown="Image_MouseLeftButtonDown"/>
</Grid>
</Window>
C# code:
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using Microsoft.Maps.MapControl.WPF;
using Microsoft.Maps.MapControl.WPF.Design;
using Microsoft.Maps.MapControl.WPF.Core;
using Microsoft.Maps.MapControl.WPF.Overlays;
using System.Windows.Controls;
namespace WPFKiosk
{
/// <summary>
/// Interaction logic for MapWindow.xaml
/// </summary>
public partial class MapWindow : Window
{
private DispatcherTimer closeTimer;
public MapWindow()
{
Pushpin pin = new Pushpin();
pin.Location = new Location(28.5383, -81.3792);
pin.Content = "text";
pin.Template = (ControlTemplate)(this.Resources["PushpinControlTemplate"]);
myMap.Children.Add(pin);
//Test 2
this.Left = 0;
this.Top = 0;
this.Topmost = true;
InitializeComponent();
LocationConverter locConverter = new LocationConverter();
// Setting the map view... aka Zoom level and center of zoom
// A string of the coordinates of a location is required
String OrlandoLoc = "28.5383,-81.3792,0.0";
// The String is then converted to a location that the map can interpret
Location center = (Location)locConverter.ConvertFrom(OrlandoLoc);
myMap.SetView(center, 13);
closeTimer = new DispatcherTimer();
closeTimer.Interval = TimeSpan.FromMinutes(2);
closeTimer.Tick += CloseTimer_Tick;
closeTimer.Start();
}
}
}

Pushpin is a ContentControl, so you may add whatever Content you like:
<m:Pushpin Location="28,-81" Content="Hello"/>
or
<m:Pushpin Location="28,-81">
<TextBlock Text="Hello"/>
</m:Pushpin>
or any more complex Content like
<m:Pushpin Location="28,-81">
<Image Source="..."/>
</m:Pushpin>

Related

Can i add elements programatically to XAML? WPF c# [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I want to add canvas elements by user input. Something like when a button is clicked, a new <Ellipse/> element is added to the XAML file, inside the Canvas.
<Canvas x:Name="GraphDisplayFrame" Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="3" Grid.RowSpan="4">
<Ellipse
Width="50"
Height="50"
Stroke="Black"
StrokeThickness="2"
Canvas.Left="100"
Canvas.Top="100" />
</Canvas>
I'm new to WPF, i'm not sure if this is the right way to do this.
The other thing i'm trying is System.Windows.Media but manipulating the XAMl file looks easier and nicer, since then the locations of the drawings are anchored to the canvas. I'm not sure if i can achieve something similar with System.Windows.Media.
So my question is in the title, but I'm open to other suggestions.
You probably want to learn about Bindings in WPF. Let's say you want your Ellipses be added by user's input (e.g. on Button click) to your Canvas. I'm not sure about Canvas usage for that purpose (it hasn't auto-alignments for child elements), so I used WrapPanel instead (to allow it align items). And we need 2 Buttons (to Add and Remove Ellipses). And I add a Label to display current amount of Ellipses that we have.
XAML:
<Window x:Class="WpfApp2.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:WpfApp2"
mc:Ignorable="d"
Name ="mainWindow"
Title="Main Window"
Width="800"
MaxWidth="800"
Height="450"
MaxHeight="450">
<Grid x:Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50*"/>
<ColumnDefinition Width="50*"/>
<ColumnDefinition Width="50*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50*"/>
<RowDefinition Height="50*"/>
<RowDefinition Height="50*"/>
<RowDefinition Height="50*"/>
</Grid.RowDefinitions>
<Label Content="{Binding ElementName=mainWindow, Path=EllipsesCount, UpdateSourceTrigger=PropertyChanged}"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Grid.Row="0"
Background="DimGray"
Foreground="White"
Margin="15,35" />
<Button x:Name="BtnAddEllipse"
Content="ADD ELLIPSE"
Grid.Row="1"
Margin="10, 25" FontSize="22" FontWeight="Bold"
Background="LightGreen"/>
<Button x:Name="BtnRemoveEllipse"
Content="REMOVE ELLIPSE"
Grid.Row="2"
Margin="10, 25" FontSize="22" FontWeight="Bold"
Background="IndianRed"/>
<WrapPanel Orientation="Horizontal"
Background="Gainsboro"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Grid.Column="1"
Grid.Row="0"
Grid.ColumnSpan="3"
Grid.RowSpan="4" >
<ItemsControl ItemsSource="{Binding ElementName=mainWindow, Path=Ellipses, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</WrapPanel>
</Grid>
</Window>
Here you see that Label.Content property is binded to some EllipsesCount property (you'll see it in code-behind below). Also as WrapPanel is binded to Ellipses property.
Code-behind: (for copypaste purpose)
using System;
using System.Linq;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
namespace WpfApp2
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
// Text for Label about Ellipses amount in collection
private object _ellipsesCount = "Current ellipses count: 0";
public object EllipsesCount
{
get => _ellipsesCount;
set
{
_ellipsesCount = "Current ellipses count: " + value;
// When we set new value to this property -
// we call OnPropertyChanged notifier, so Label
// would be "informed" about this change and will get new value
OnPropertyChanged(nameof(EllipsesCount));
}
}
// Collection for Ellipses
private ObservableCollection<Ellipse> _ellipses;
public ObservableCollection<Ellipse> Ellipses
{
get => _ellipses;
set
{
_ellipses = value;
OnPropertyChanged(nameof(Ellipses));
}
}
// Hanlder, which would notify our Controls about property changes, so they will "update" itself with new values
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
// Just for random colors
private readonly Random random = new Random();
public MainWindow()
{
InitializeComponent();
// Initialize collection of Ellipses
Ellipses = new ObservableCollection<Ellipse>();
// Handle when collection is changed to update Label
// with a new amount of Ellipses
Ellipses.CollectionChanged += delegate
{
// Update counter of ellipses when new one added or existing removed
EllipsesCount = Ellipses.Count;
};
BtnAddEllipse.Click += delegate
{
// Create an Ellipse with random stroke color
var ellipse = new Ellipse
{
Width = 50,
Height = 50,
Margin = new Thickness(3),
Stroke = new SolidColorBrush(Color.FromRgb((byte)random.Next(255), (byte)random.Next(255), (byte)random.Next(255))),
StrokeThickness = 3
};
// Add to collection of ellipses
Ellipses.Add(ellipse);
};
BtnRemoveEllipse.Click += delegate
{
// Check, that Ellipses collection isn't null and empty,
// so we can remove something from it
if (Ellipses?.Count > 0)
Ellipses.Remove(Ellipses.Last()); // Removing last element
};
}
}
}
So at result you see, actually, "content of collection of Ellipses", without adding Ellipses directly to window. Binding makes WrapPanel to use collection of Ellipses as source of child elements, that should be in that WrapPanel (instead of original my answer, where we add Ellipse to Canvas as Children).
ORIGINAL answer.
Yes, you can. For example (based on your XAML):
XAML (empty window):
<Window x:Class="WPFApp.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:WPFApp"
mc:Ignorable="d">
<!-- No even Grid here -->
</Window>
Code-behind (check comments also):
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Setting Window properties (they not exists in XAML)
// XAML: <Window ... Title="Main Window" Height="450" Width="800">...
this.Title = "Main Window";
this.Height = 450;
this.Width = 800;
// Create main Grid and register some its name
// XAML: ...
var mainGrid = new System.Windows.Controls.Grid();
this.RegisterName("MainGrid", mainGrid);
// Add row and column definitions (as Canvas below needs, at least 4 rows and 3 columns)
for (int i = 0; i < 4; i++)
{
mainGrid.RowDefinitions.Add(new System.Windows.Controls.RowDefinition { Height = new GridLength(50, GridUnitType.Star) });
if (i < 3) // Needn't 4th column
mainGrid.ColumnDefinitions.Add(new System.Windows.Controls.ColumnDefinition { Width = new GridLength(50, GridUnitType.Star) });
}
// Create Canvas and register its name too
// XAML: ...
var canvas = new System.Windows.Controls.Canvas
{
// Just to be able see it at Window
Background = System.Windows.Media.Brushes.LightGray
};
this.RegisterName("GraphDisplayFrame", canvas);
canvas.SetValue(System.Windows.Controls.Grid.ColumnProperty, 1);
canvas.SetValue(System.Windows.Controls.Grid.RowProperty, 0);
canvas.SetValue(System.Windows.Controls.Grid.ColumnSpanProperty, 3);
canvas.SetValue(System.Windows.Controls.Grid.RowSpanProperty, 4);
// Create Ellipse (child canvas element)
// XAML: ...
var ellipse = new System.Windows.Shapes.Ellipse
{
Width = 50,
Height = 50,
Stroke = System.Windows.Media.Brushes.Black,
StrokeThickness = 2
};
ellipse.SetValue(System.Windows.Controls.Canvas.LeftProperty, 100D);
ellipse.SetValue(System.Windows.Controls.Canvas.TopProperty, 100D);
// Add child Ellipse to Canvas
canvas.Children.Add(ellipse);
// or you already can find Canvas by its name:
(this.FindName("GraphDisplayFrame") as System.Windows.Controls.Canvas).Children.Add(ellipse);
// Add Canvas to MainGrid. Find Grid by its registered name too
(this.FindName("MainGrid") as System.Windows.Controls.Grid).Children.Add(canvas);
// Set main Grid as window content
this.Content = mainGrid;
}
}
So, as you can see, XAML markuping is quite more compact, that code-behinded one.

How to change all items in the ListBox

I use DataTemplate to repeatedly generate the content of my ListBox.
The xaml code is as below:
<DataTemplate x:Key="singleUnit">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding fileName}" FontSize="20" Foreground="{Binding color}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<TextBlock/>
</StackPanel>
</DataTemplate>
<ListBox Name="MyListBox" Width="300" Height="600">
</ListBox>
And the cs code is:
private void Show()
{
const int TotalCount = 100;
for (int i = 0; i < TotalCount; i++)
{
ContentControl cc = new ContentControl();
cc.ContentTemplate = this.Resources["singleUnit"] as DataTemplate;
DataModel dm = new DataModel();
dm.fileName = "myfile" + i;
dm.color = new SolidColorBrush(Colors.Blue);
cc.Content = dm;
MyListBox.Items.Add(cc);
}
MyListBox.ScrollIntoView(MyListBox.Items[TotalCount / 2]);
}
Above code will generate below UI:
And I hope to change all the item's color: currently each item, the fileName's foreground color is blue. And I hope to change it to like green when the button is pressed.
This is like that user changes the color theme with some selection operation. And when the color changes, all the other things should be not changed, e.g. the position of the scroll bar.
The difficulty is that I use template to generate the content, and how to iterate each item and modify it.
I put the workable demo code on my Github:
https://github.com/tomxue/ChangeListBox.git
You could start from it.
Thanks!
I made your code work but it is still not perfectly right as you should have per each view a view-model and bind between them.
Your MainForm - should have a MainFormViewModel.
Your File Items - should have VmFile (or ViewModelFile as I wrote in the example)
You should be using ICommand to bind the button and not by having an event as you did.
Shortly put, I don't think you are working correct with MVVM, I advise you to read more about MVVM.
Copy to your .xaml file:
<Window x:Class="WpfApp14.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:WpfApp14"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ListBox Name="MyListBox" Width="300" Height="600">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FileName}" FontSize="20" Foreground="{Binding Color}"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
<TextBlock/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="Change color theme" HorizontalAlignment="Left" Margin="56,126,0,0" VerticalAlignment="Top" Width="164" Click="Button_Click" Height="36"/>
</Grid>
</Window>
Copy to your .cs file:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp14
{
public class ViewModelFile : INotifyPropertyChanged
{
private string filename;
private SolidColorBrush solidColorBrush;
public event PropertyChangedEventHandler PropertyChanged;
public string FileName
{
get =>filename;
set
{
filename = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FileName)));
}
}
public SolidColorBrush Color
{
get => solidColorBrush;
set
{
solidColorBrush = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Color)));
}
}
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Refresh();
}
private void Refresh()
{
const int TotalCount = 100;
for (int i = 0; i < TotalCount; i++)
{
ViewModelFile vm = new ViewModelFile
{
FileName = "myfile" + i,
Color = new SolidColorBrush(Colors.Blue)
};
MyListBox.Items.Add(vm);
}
MyListBox.ScrollIntoView(MyListBox.Items[TotalCount / 2]);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Do something to change all fileName items' forground color to red.
// For example if user changes the color theme, and we should just change some UI color
// while not changing any other part, e.g. the position of scrollbar
foreach (var item in MyListBox.Items)
((ViewModelFile)item).Color = new SolidColorBrush(Colors.Red);
}
}
}

How to create WPF image SVG from Resource in code c#?

I converted image svg to xaml, next I save it in string resource "printer".
From code-behind I want to create this image /printer.svg now printer.xaml/ and add it to Canvas as child.
Please help me how to do it the best in c# code?
Thank you
Piotr
I do something wrong...
string resVal = Resource1.ResourceManager.GetString("printer");
UserControl u = new UserControl();
u.DataContext = resVal;
Canvas.SetLeft(u, 150);
Canvas.SetTop(u, 150);
front_canvas.Children.Add(u);
And my printer.svg converted to xaml
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="358" Width="368">
<Viewbox Stretch="Fill" Width="107.9580078125" Height="107.9580078125">
<Canvas Width="407.9580078125" Height="407.9580078125">
<Canvas>
<Canvas>
<Canvas>
<Path Fill="Black" StrokeThickness="1" Data="F1M84.979,307.916L33.153,307.916C14.873,307.916,0,293.04,0,274.756L0.197,149.068C0.197,130.794,15.075,115.917,33.363,115.917L60.479,115.917C64.897,115.917 68.479,119.499 68.479,123.917 68.479,128.335 64.897,131.917 60.479,131.917L33.363,131.917C23.898,131.917,16.197,139.617,16.197,149.081L16,274.768C16,284.218,23.695,291.916,33.153,291.916L84.979,291.916C89.397,291.916 92.979,295.498 92.979,299.916 92.979,304.334 89.397,307.916 84.979,307.916z"/>
..............
Suppose an .svg image is converted to the .xaml format, "decorated" with an user control and saved to the application resources.
String resource name: UserControl1
String resource value:
<UserControl
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Margin="10">
<Path x:Name="shape1" Stretch="Fill" Fill="BlueViolet" StrokeThickness="1"
Data="m 187.906,186.34 c 1.282,7.861 2.571,15.76 3.859,23.646 3.836,23.54 7.629,46.766 11.073,67.894 7.675,47.046 13.162,80.674 13.162,80.674 -0.751,-0.653 -1.489,-1.316 -2.232,-1.967 0.139,0.857 0.275,1.721 0.414,2.586 1.056,0.94 2.117,1.88 3.187,2.822 0.733,-1.112 1.451,-2.23 2.184,-3.338 -0.145,-0.865 -0.296,-1.73 -0.435,-2.593 -0.516,0.776 -1.022,1.555 -1.535,2.338 0,0 -5.566,-33.659 -13.357,-80.744 -3.496,-21.139 -7.338,-44.378 -11.237,-67.929 -1.211,-7.313 -2.422,-14.64 -3.629,-21.935 7.294,1.208 14.619,2.421 21.933,3.631 23.552,3.898 46.79,7.74 67.931,11.237 47.084,7.792 80.743,13.355 80.743,13.355 -0.782,0.514 -1.564,1.018 -2.34,1.536 0.863,0.14 1.729,0.291 2.598,0.436 1.105,-0.731 2.223,-1.452 3.337,-2.184 -0.945,-1.071 -1.885,-2.131 -2.825,-3.188 -0.864,-0.139 -1.727,-0.275 -2.588,-0.413 0.653,0.743 1.317,1.479 1.971,2.232 0,0 -33.628,-5.486 -80.677,-13.164 -21.127,-3.442 -44.352,-7.234 -67.891,-11.074 -7.887,-1.286 -15.787,-2.574 -23.646,-3.858" />
</Grid>
</UserControl>
The following code demonstrate how load the user control from resources and add it to the main window:
// MainWindow.xaml.cs
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Xml;
namespace LoadFromXamlDynamically
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
StringReader stringReader = new StringReader(Properties.Resources.UserControl1);
using (XmlReader xmlReader = XmlReader.Create(stringReader))
{
var control = (UserControl)System.Windows.Markup.XamlReader.Load(xmlReader);
LayoutRoot.Children.Add(control);
}
}
}
}
MainWindow.xaml
<Window ...>
<Grid x:Name="LayoutRoot">
</Grid>
</Window>

How to get C# WPF MVVM Screensaver use dual monitor?

I am looking for an answer howto get a C#-WPF-MVVM-Screensaver-View on dual and more monitors running. I read several tutorials on webpages and answers here. However, never the coding samples worked on wpf.
Have someone a code exmple that works for wpf and Model View ViewModel Pattern?
I appreciate your help and thank you.
Thanks. I did it on Windows 10.
Create new WPF Window project for C#
Remove the startupuri / startuplocation from app.xaml.
Add a startup method to app.xaml.
4.
<Application x:Class="SeveralDisplays.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SeveralDisplays"
Startup="OnStartup">
<Application.Resources>
</Application.Resources>
</Application>
using System.Drawing;
using System.Windows;
using System.Windows.Forms;
using Application = System.Windows.Application;
namespace SeveralDisplays
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private void OnStartup(object sender, StartupEventArgs e)
{
Window mainWindow1 = new MainWindow();
Window mainWindow2 = new MainWindow2();
Screen s1 = Screen.AllScreens[0];
Screen s2 = Screen.AllScreens[1];
Rectangle r1 = s1.WorkingArea;
Rectangle r2 = s2.WorkingArea;
mainWindow1.Top = r1.Top;
mainWindow1.Left = r1.Left;
mainWindow2.Top = r2.Top;
mainWindow2.Left = r2.Left;
mainWindow1.Show();
mainWindow2.Show();
mainWindow2.Owner = mainWindow1;
}
}
}
add two classes and ensure they are window-classes.
First / Main view, do not change here too much
<Window x:Class="SeveralDisplays.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:SeveralDisplays"
mc:Ignorable="d"
Loaded="MainWindow_OnLoaded"
Title="MainWindow" Height="350" Width="525">
<Grid>
</Grid>
</Window>
first window code behind
using System.Windows;
namespace SeveralDisplays
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Maximized;
WindowStyle = WindowStyle.None;
ShowInTaskbar = false;
}
}
}
Second xaml as window
<Window x:Class="SeveralDisplays.MainWindow2"
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:SeveralDisplays"
mc:Ignorable="d"
Title="MainWindow2"
WindowStartupLocation="Manual"
WindowStyle="None"
WindowState="Maximized"
Height="300" Width="300">
<Grid>
</Grid>
</Window>
Code behind:
using System.Windows;
namespace SeveralDisplays
{
public partial class MainWindow2 : Window
{
public MainWindow2()
{
InitializeComponent();
}
}
}
you can do this simplified and smart. I use only a method inside app.xaml.cs
/// <summary>
/// Shows the screensaver on every monitor. This is a multi monitor
/// application.
/// </summary>
private void ShowScreenSaver()
{
ClockWindow ownerWindow = null;
// Creates window on other screens.
foreach (System.Windows.Forms.Screen screen in System.Windows.Forms.Screen.AllScreens)
{
ClockWindow window = new ClockWindow(screen.Bounds.Width,
screen.Bounds.Height);
// Primary screen does not have WindowsStartupLocation.
if (screen.Primary)
{
// Maximizes screen.
window.WindowState = WindowState.Maximized;
ownerWindow = window;
}
else
{
// Other screens need a WindowStartupLocation on manual.
window.WindowStartupLocation = WindowStartupLocation.Manual;
System.Drawing.Rectangle location = screen.Bounds;
window.Top = location.Top;
window.Left = location.Left - 480;
window.Width = location.Width;
window.Height = location.Height;
}
window.Show();
}
// Sets every other screen owned to prmary window.
// It closes all windows at once.
foreach (Window window in Current.Windows)
{
if (window != ownerWindow)
{
window.Owner = ownerWindow;
}
}
}
Here I added a View, which I initializes for several displays.
<Window x:Class="Clock_ScreenSaver.Views.ClockWindow"
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:Clock_ScreenSaver.Views"
mc:Ignorable="d"
Title="ClockWindow"
Height="{Binding DisplayHeight}"
Width="{Binding DisplayWidth}"
AllowsTransparency="True"
Background="Black"
Cursor="None"
ShowInTaskbar="False"
KeyDown="ClockWindow_KeyDown"
MouseMove="ClockWindow_MouseMove"
MouseDown="ClockWindow_MouseDown"
Closing="ClockWindowClosing"
Loaded="ClockWindowLoaded"
WindowStyle="None"
ResizeMode="NoResize">
<Grid Name="WindowGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="300"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="300"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Row="1" Grid.Column="1" CornerRadius="360" BorderBrush="#FFDF66" BorderThickness="5" Background="#2D2D30">
<StackPanel>
<Label Foreground="#FFDF66" Margin="0,15,0,0" FontSize="25" FontFamily="Arial" HorizontalAlignment="Center">DIGICLOCK</Label>
<StackPanel Background="#3F3F46" Margin="0,20,0,5" Width="280" Height="100">
<Label Content="{Binding ClockTime}" Name="timelbl" Margin="0,20,0,0" Foreground="#FFDF66" FontSize="40" FontFamily="Arial" HorizontalAlignment="Center"></Label>
</StackPanel>
<StackPanel Background="#3F3F46" Margin="0,0,0,10" Width="280" Height="50">
<Label Content="{Binding ClockDate}" Name="datelbl" Margin="0,8,0,0" Foreground="#FFDF66" FontSize="20" FontFamily="Arial" HorizontalAlignment="Center"></Label>
</StackPanel>
<Button Width="60" Padding="5,5,5,5" Background="#FFDF66" FontSize="10" FontFamily="Arial" Foreground="#333333" BorderThickness="0" Name="QuitBtn" Click="QuitBtn_Click">
Quit
</Button>
</StackPanel>
</Border>
</Grid>
</Window>

Replace a button with a picture when clicked and then create a new button on top of picture in WPF

I am wanting to create a small program that would let me select from a few images of interconnecting pieces to create what is essentially a path. That idea would be to have a starting piece with a button to where you could connect the next piece of the path. When clicked, this button would offer up a selection of the options that can be placed there and then the selected image would be placed and the button moved to the new end of the path.
My problem is that my c# experience is so far limited to static UI and manipulating text fields or entire new windows. I don't have a clue about where to start to make a UI in which buttons are moved and images are placed after the initial start of the program. I thought maybe using the grid control and some code to manipulate it might be the answer, but really don't know the commands to do such. I have been using WPF for my previous programs, and assume it would still be viable in this case.
Would anyone be able to point me in the right direction to figuring out how to dynamically control a section of the program's window in order to accomplish my goal? I am sorry for the semi-vague question but this is well out of my wheelhouse as a still very new hobbyist programmer.
Here's a quick, rather crude example, but it shows some basics of adding and positioning controls at runtime.
Things to note:
Add controls to a Canvas if you want to be able to position x,y explicitly.
I used UserControls for location items, and just added instances
If you're building a game, and if it's any significant size and complexity, don't use WPF. I've been there, done that, built a full multiplayer space arcade/action game on it. It's too slow for games.
Here's the code dump below.
//PathBuilding.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TravianResourceProd" x:Class="TravianResourceProd.PathBuilding"
Title="PathBuilding" Height="466.377" Width="621.509">
<Grid x:Name="drawingGrid" Background="#FFC2C2C2" >
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="0*"/>
</Grid.ColumnDefinitions>
<Canvas Background="#FFB3B3B3" Margin="0,0,0,-0.377" x:Name="DrawCanvas" MouseMove="DrawCanvas_MouseMove" MouseUp="Grid_MouseUp">
<local:ActiveLocation x:Name="primarySegment" HorizontalAlignment="Left" VerticalAlignment="Top" Loaded="ActiveLocation_Loaded" Canvas.Left="67" Canvas.Top="98"/>
</Canvas>
</Grid>
</Window>
//PathBuilding.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace TravianResourceProd
{
/// <summary>
/// Interaction logic for PathBuilding.xaml
/// </summary>
public partial class PathBuilding : Window
{
public PathBuilding()
{
InitializeComponent();
_ConnectorLine = new Line();
_ConnectorLine.Stroke = new SolidColorBrush(Colors.DarkBlue);
_ConnectorLine.Visibility = System.Windows.Visibility.Hidden;
_locationSelector = new LocationOptions();
_locationSelector.Visibility = System.Windows.Visibility.Hidden;
DrawCanvas.Children.Add(_ConnectorLine);
DrawCanvas.Children.Add(_locationSelector);
}
private Line _ConnectorLine;
private bool _AddMode = false;
private LocationOptions _locationSelector;
private void ActiveLocation_Loaded(object sender, RoutedEventArgs e)
{
primarySegment.btnAddSegment.Click += (object sender1, RoutedEventArgs e1) =>
{
//show the type selector
_locationSelector.Visibility = System.Windows.Visibility.Visible;
var loc = _locationSelector.TransformToAncestor(drawingGrid)
.Transform(new Point(0, 0));
Canvas.SetLeft(_locationSelector, Mouse.GetPosition(DrawCanvas).X + 80);
Canvas.SetTop(_locationSelector, Mouse.GetPosition(DrawCanvas).Y - 50);
};
_locationSelector.btnTypeOne.Click += (object s, RoutedEventArgs e2) =>
{
_AddMode = true;
_ConnectorLine.Visibility = System.Windows.Visibility.Visible;
_locationSelector.Visibility = System.Windows.Visibility.Hidden;
};
}
private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
{
if (!_AddMode)
return;
_AddMode = false;
_ConnectorLine.Visibility = System.Windows.Visibility.Hidden;
//Add the one we picked
var oldLoc = new OldLocation();
Canvas.SetLeft(oldLoc, Canvas.GetLeft(primarySegment));
Canvas.SetTop(oldLoc, Canvas.GetTop(primarySegment));
DrawCanvas.Children.Add(oldLoc);
//Add a line connecting old to new
var newestLine = new Line();
newestLine.Visibility = System.Windows.Visibility.Visible;
newestLine.Stroke = new SolidColorBrush(Colors.Brown);
newestLine.X1 = _ConnectorLine.X1;
newestLine.Y1 = _ConnectorLine.Y1;
newestLine.X2 = _ConnectorLine.X2 + 40;
newestLine.Y2 = _ConnectorLine.Y2 + 50;
DrawCanvas.Children.Add(newestLine);
//Move the active/primary to the new location
Canvas.SetLeft(primarySegment, e.GetPosition(this).X);
Canvas.SetTop(primarySegment, e.GetPosition(this).Y);
}
private void DrawCanvas_MouseMove(object sender, MouseEventArgs e)
{
try
{//reposition the line going from active location to mouse
_ConnectorLine.X1 = Canvas.GetLeft(primarySegment) + 70;
_ConnectorLine.Y1 = Canvas.GetTop(primarySegment) + 50;
_ConnectorLine.X2 = e.GetPosition(this).X - 5;
_ConnectorLine.Y2 = e.GetPosition(this).Y - 5;
}
catch (Exception)
{
}
}
}
}
//LocationOptions.xaml
<UserControl x:Class="TravianResourceProd.LocationOptions"
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"
mc:Ignorable="d" Height="109.359" Width="117.057">
<Grid Margin="0,0,-0.17,0.094">
<Button x:Name="btnTypeOne" Content="Type One" HorizontalAlignment="Left" VerticalAlignment="Top" Width="117" Height="33" Margin="0,0,-0.17,0" />
<Button x:Name="btnTypeTwo" Content="Type Two" HorizontalAlignment="Left" VerticalAlignment="Top" Width="117" Margin="0,38,-0.17,0" Height="33" />
</Grid>
</UserControl>
//OldLocation.xaml
<UserControl x:Class="TravianResourceProd.OldLocation"
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"
mc:Ignorable="d" Height="80" Width="80">
<Grid>
<Ellipse Stroke="#FF686868" StrokeThickness="8">
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF373737" Offset="1"/>
<GradientStop Color="#FF929292"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
</UserControl>
//ActiveLocation.xaml
<UserControl x:Class="TravianResourceProd.ActiveLocation"
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"
mc:Ignorable="d" Height="80" Width="80">
<Grid>
<Ellipse Stroke="#FF1A9000" StrokeThickness="6">
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF62745E" Offset="1"/>
<GradientStop Color="#FF929292"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Button x:Name="btnAddSegment" Content="" HorizontalAlignment="Left" VerticalAlignment="Top" Width="20" Height="22" FontSize="30" Margin="60,30,-0.302,0"/>
</Grid>
</UserControl>

Categories

Resources