|
Why not just use the Ribbon controls (e.g. "split menu item" that looks like a "button")?
You're duplicating existing functionality.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
Gerry Schmitz wrote: Why not just use the Ribbon controls (e.g. "split menu item" that looks like a "button")?
Have you ever used these Ribbon controls? I have. WAY WAY WAY too over cooked.
That's exactly what I'm trying to avoid - paying hundreds or thousands of dollars for control suites that have a limited set of controls and are either way too over engineered or don't do enough.
1) You almost never get all the controls you want, so you usually then have to include multiple third party controls into your app.
2) Many of them are crap (Infragistics is a good example), Telerik is OK but lacks some things
3) For what you pay for you just don't get enough. And I'm talking WITHOUT the source.
4) Tech support is almost always a nightmare.
If I have the code, and created my own suite, then I can modify it any way I want and not rely on some other vendor.
Gerry Schmitz wrote: You're duplicating existing functionality.
Not necessarily. Assuming you could purchase a complete set of controls that functioned EXACTLY the way you want, then you would be right. But I've yet to find a set of controls that is that complete.
Again, if it's just a set of controls, then how much 'functionality' are we talking a about?? If we were talking about a specialized API that was specific to some app or piece of equipment, then writing a new one would make no sense. But for a set of controls, I think I have the advantage here.
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Paying?
These are the "native" WPF Ribbon controls:
xmlns:ribbon="clr-namespace:System.Windows.Controls.Ribbon;assembly=System.Windows.Controls.Ribbon"
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
The only one talking about a Ribbon is you.
I'm talking about a Suite of controls. Most of them you buy are totally inaduquate.
But anyway, you never answered my original question
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I asked a "question": I was suggesting you could save time by using existing (free) "split buttons", etc. (that you could style).
You keep talking about $; while I said to use what is already in the framework.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
I understand why you asked. I just think this discussion went way off the rails. At no point was my original question dealt with. It seems you we're trying to guide me down a different approach.
Gerry Schmitz wrote: use what is already in the framework.
The controls I'm working on don't exist in the framework - that's why I'm creating them.
One other reason I want to develop these controls myself is really for the learning experience.
Thanks for your input.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 19-May-17 11:21am.
|
|
|
|
|
"Don't exist in the framework..."
We must be using "different" frameworks then:
<ribbon:RibbonSplitButton Label="Color 1" SmallImageSource="Images/RightArrowShort_Green16.png" LargeImageSource="Images/RightArrowShort_Green32.png" >
<ribbon:RibbonGallery SelectedValue="Green"
SelectedValuePath="Content"
MaxColumnCount="1">
<ribbon:RibbonGalleryCategory>
<ribbon:RibbonGalleryItem Content="Green" Foreground="Green" />
<ribbon:RibbonGalleryItem Content="Blue" Foreground="Blue" />
<ribbon:RibbonGalleryItem Content="Orange" Foreground="Orange" />
</ribbon:RibbonGalleryCategory>
</ribbon:RibbonGallery>
</ribbon:RibbonSplitButton>
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
OK, we definitely went off the rails in this discussion as we never got around to the styling question.
For some reason you are focusing on "existing functionality" where my question is only about styling.
So, I created a new question that covers this topic using a generic UserControl.
Again, I am solely looking for an understanding of how to style a control like this.
Thanks!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
You went beyond styling; you claimed to be creating a (new) suite of controls; that's were I questioned why.
If you were painting a dog house, and I thought there was a problem with your dog house, I would need to point it out; even if I loved the color.
It's in my nature.
Living through reason.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
As to actual styling, I strip all styling from the existing controls, and start applying it at the "application" level to get the effect I want (App.xaml: Application.Resources).
Using "dynamic resources" judiciously, I can change my "theme" (background and forground) on the fly (holly red and green, for example).
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
So when you have a control that is a composite of other controls, compiled into another assembly, how do you create a style that can be applied to that control? Do you have to name the parts of the control and target them that way?
Like I said in my other example, assume you have a UserControl a ListBox, a CheckBox, and a button, call it Widget... Widget is compiled into another assembly.
For ApplicationA I may want the background of the listbox to be red, and the button to be round. Yet for ApplicationB it could look entirely different.
If your styling is at the application level, how do those individual pieces get styled? If you just rely on TargetType, the ALL buttons would have that look. That leaves specifically targeting each individual part of the control.
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I want my entire application to have a similar look and feel; as I expect the user does.
It's iterative.
Style the most common elements first: TextBoxes; TextBlocks; FontFamily; etc. at the "app" level.
Anchor all your elements in a dummy form / window and see how they look.
The ones that need special handling (negative margins; for example) get styles at the "level" most appropriate: element; parent element; user control; window; dll).
I'm current working on a User Control that does it's own keyboard handling; creates / deletes siblings on the fly; changes color based on "mode"; etc. In this case, I expect a lot of customizing at the control level but still expect to "inherit" colors and fonts from a "higher resource".
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
I've got this code that changes the theme during runtime
private void ApplyTheme()
{
ResourceDictionary resources = null;
string fileName = string.Empty;
switch (SelectedThemeName)
{
case "Black":
fileName = "Theme_Black.xaml";
break;
case "Blue":
fileName = "Theme_Blue.xaml";
break;
}
if (fileName == string.Empty)
{
throw new Exception(string.Format("Resource dictionary for theme name {0} not found", SelectedThemeName));
}
fileName = "..\Themes\" + fileName;
if (!File.Exists(fileName))
{
throw new Exception(string.Format("Theme name {0} not found", SelectedThemeName));
}
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
resources = (ResourceDictionary)XamlReader.Load(fs);
}
Application.Current.Resources = resources;
}
The problem is that it relies on a physical file to exist at runtime. Is there a better way to do this?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Hello.
I am trying to make a small "book library" application where readers can rent books.
My application is tructured like this: 4 views(with their associated viewmodels). MainWindow is the main view. Inside it i have a content control where i display the other 3 secondary/child views:HomeView, BookManagingView, ReaderManagingView. The default selected view is HomeView, where i have 2 ListViews(for Readers and Books), and some buttons. In my ReaderManagingView i have some textboxes and buttons to add/update/delete readers from database and listview.
The database has 3 tables: Books, Readers, and RentedBooks.
What i am trying to do is: when i add/update/delete users from my database, i want my changes to reflect (almost)instantly in my ListView.
The problem: The changes are visible only after i restart the application. What should i do, so that my Readers ListView updates after i add/update/delete a user?
Here is some code:
HomeView:
<ListView x:Name="listviewReaders" ItemsSource="{Binding ReadersList, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" SelectedItem="{Binding SelectedReader, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="160" Margin="25,23,315,40">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FullName}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ReaderManagingView:
<Grid>
<TextBox x:Name="txtBxFullName" HorizontalAlignment="Left" Height="23" Margin="25,27,0,0" TextWrapping="Wrap" Text="{Binding CurrentReader.FullName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="txtBxSerialNumber" HorizontalAlignment="Left" Height="23" Margin="25,55,0,0" TextWrapping="Wrap" Text="{Binding CurrentReader.SerialNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="txtBxIdNumber" HorizontalAlignment="Left" Height="23" Margin="25,83,0,0" TextWrapping="Wrap" Text="{Binding CurrentReader.IdNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="txtBxAdress" HorizontalAlignment="Left" Height="23" Margin="25,111,0,0" TextWrapping="Wrap" Text="{Binding CurrentReader.Adress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="txtBxAltContactMethods" HorizontalAlignment="Left" Height="23" Margin="25,139,0,0" TextWrapping="Wrap" Text="{Binding CurrentReader.AltContactMethods, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
<Button x:Name="btnAddReader" Command="{Binding AddR, UpdateSourceTrigger=PropertyChanged}" Content="Add" HorizontalAlignment="Left" Margin="25,177,0,0" VerticalAlignment="Top" Width="60"/>
<Button x:Name="btnDeleteReader" Command="{Binding DeleteR, UpdateSourceTrigger=PropertyChanged}" Content="Delete" HorizontalAlignment="Left" Margin="155,177,0,0" VerticalAlignment="Top" Width="60"/>
<Button x:Name="btnClearReader" Command="{Binding ClearR, UpdateSourceTrigger=PropertyChanged}" Content="Clear" HorizontalAlignment="Left" Margin="220,177,0,0" VerticalAlignment="Top" Width="60"/>
<Button x:Name="btnEditReader" Command="{Binding EditR, UpdateSourceTrigger=PropertyChanged}" Content="Save" HorizontalAlignment="Left" Margin="90,177,0,0" VerticalAlignment="Top" Width="60"/>
</Grid>
HomeVM:
public class HomeViewModel : ViewModelBase
{
private Reader selectedReader;
private Book selectedBook;
private BookListFilter selectedFilter;
private ObservableCollection<Book> bookList;
private ObservableCollection<Reader> readerList;
private IEnumerable<BookListFilter> bookLstItemSrc;
public HomeViewModel(MainWindowViewModel _mwvm)
{
Mwvm = _mwvm;
SelectedReader = new Reader();
SelectedBook = new Book();
SelectedFilter = BookListFilter.AllBooks;
BookDBDataContext rdb = new BookDBDataContext();
ReadersList = new ObservableCollection<Reader>(rdb.Readers);
GetBookList();
EditReaderSwitch = new DefCommand(EditReaderInfo);
EditBookSwitch = new DefCommand(EditBookInfo);
}
public DefCommand EditReaderSwitch { get; private set; }
public DefCommand EditBookSwitch { get; private set; }
public MainWindowViewModel Mwvm { get; set; }
public ObservableCollection<Reader> ReadersList
{
get { return readerList; }
set
{
if (readerList != value)
{
readerList = value;
RaisePropertyChanged();
}
}
}
ReaderManagingViewModel:
public class ReaderManagingViewModel : ViewModelBase
{
private static Reader currentReader;
public ReaderManagingViewModel(HomeViewModel hvm)
{
if (CurrentReader == null)
CurrentReader = new Reader();
CurrentReader = hvm.SelectedReader;
AddR = new DefCommand(AddReader);
EditR = new DefCommand(UpdateReader);
DeleteR = new DefCommand(DeleteReader);
ClearR = new DefCommand(ClearReaderFields);
}
public Reader CurrentReader
{
get { return currentReader; }
set
{
if (currentReader != value)
{
currentReader = value;
RaisePropertyChanged();
}
}
}
public DefCommand AddR { get; private set; }
public DefCommand EditR { get; private set; }
public DefCommand DeleteR { get; private set; }
public DefCommand ClearR { get; private set; }
private void AddReader()
{
BookDBDataContext db = new BookDBDataContext();
Reader rObj = new Reader();
rObj.FullName = CurrentReader.FullName;
rObj.SerialNumber = CurrentReader.SerialNumber;
rObj.Id = CurrentReader.Id;
rObj.Adress = CurrentReader.Adress;
rObj.AltContactMethods = CurrentReader.AltContactMethods;
try
{
db.Readers.InsertOnSubmit(rObj);
db.Readers.Context.SubmitChanges();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private void UpdateReader()
{
BookDBDataContext db = new BookDBDataContext();
var qry = from reader in db.Readers
where reader.Id == CurrentReader.Id
select reader;
foreach (Reader r in qry)
{
r.FullName = CurrentReader.FullName;
r.SerialNumber = CurrentReader.SerialNumber;
r.IdNumber = CurrentReader.IdNumber;
r.Adress = CurrentReader.Adress;
r.AltContactMethods = CurrentReader.AltContactMethods;
}
try
{
db.SubmitChanges();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private void DeleteReader()
{
BookDBDataContext db = new BookDBDataContext();
var rbTbl = (from r in db.RentedBooks
where r.ReaderId == CurrentReader.Id
select r);
var rTbl = (from r in db.Readers
where r.Id == CurrentReader.Id
select r).SingleOrDefault();
try
{
foreach (var rbr in rbTbl)
{
db.RentedBooks.DeleteOnSubmit(rbr);
}
db.Readers.DeleteOnSubmit(rTbl);
db.SubmitChanges();
}
catch(Exception e)
{
Console.WriteLine(e);
}
Console.WriteLine("deleting");
}}
|
|
|
|
|
The problem is that the context you're using to make the changes has no connection to the ObservableCollection<T> which holds the current list of readers.
You need some way for the ReaderManagingViewModel to notify the HomeViewModel when something changes.
The standard approach would be to use a mediator service:
MVVM Mediator Pattern[^]
A Mediator Prototype for WPF Apps | Josh Smith on WPF[^]
Alternatively, as a "quick-and-dirty" approach, you could store the HomeViewModel instance passed to the ReaderManagingViewModel constructor, and call public methods on that instance to add, update and delete readers from the list.
Depending on your requirements, you could either have a single method to reload the entire list:
public void LoadReaders()
{
using (BookDBDataContext rdb = new BookDBDataContext())
{
ReadersList = new ObservableCollection<Reader>(rdb.Readers);
}
}
Or you could have separate methods to add, update and delete the readers:
public void AddReader(Reader readerToAdd)
{
ReadersList.Add(readerToAdd);
}
public void UpdateReader(Reader readerToUpdate)
{
var reader = ReadersList.FirstOrDefault(r => r.Id == readerToUpdate.Id);
if (reader != null)
{
reader.FullName = readerToUpdate.FullName;
reader.SerialNumber = readerToUpdate.SerialNumber;
reader.IdNumber = readerToUpdate.IdNumber;
reader.Adress = readerToUpdate.Adress;
reader.AltContactMethods = readerToUpdate.AltContactMethods;
}
else
{
ReadersList.Add(readerToUpdate);
}
}
public void DeleteReader(Reader readerToDelete)
{
var readerToRemove = ReadersList.FirstOrDefault(r => r.Id == readerToDelete.Id);
if (readerToRemove != null) ReadersList.Remove(readerToRemove);
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thank You! I will try that.
|
|
|
|
|
i used the LoadReaders method, and it works.
Thank you very much!
|
|
|
|
|
Anyone know if there's any official MS documentation that visually describes WPF control templates?
Something like this is what I'm after.
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
"A picture paints a thousand words" - which is probably why they're hard to find in M$ documentation!
However - is this what you're after? WPF Graphics Rendering Overview[^] (search for Control Template)
|
|
|
|
|
I was thinking of something where all the parts of the default set of WPF controls is outlined visually.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Ah sorry. Don't think I've ever seen anything "official" along those lines. Best stuff I saw was part of a course and I didn't (couldn't) "grab" it
|
|
|
|
|
Maybe I should write up an article on it
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
The closest the documentation gets to describing the templates lies in this section[^] of the MSDN.
This space for rent
|
|
|
|
|
Here's my control template
<UserControl.Resources>
<pre>
<ControlTemplate x:Key="myTemplate"
TargetType="{x:Type ComboBox}">
<Grid>
<Popup x:Name="PART_Popup"
IsOpen="{TemplateBinding IsDropDownOpen}">
<Button Height="100"
Width="100"
Content="Hello"/>
</Popup>
</Grid>
</ControlTemplate>
and my usage:
<ComboBox Grid.Row="0"
Grid.Column="3"
Background="Red"
x:Name="comboBox"
Width="150"
Template="{Binding StringFormat=myTemplate}">
The ComboBox does not appear. if I remove the Template line it appears.
What am I doing wrong?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
You're using StringFormat. That's, as you would expect, for formatting strings. Try using Template="{StaticResource myTemplate}" instead.
This space for rent
|
|
|
|
|