dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.04k stars 1.17k forks source link

Add implicit conversion between System.Drawing.Color and System.Windows.Media.Color #752

Open dotMorten opened 5 years ago

dotMorten commented 5 years ago

Currently System.Windows.Media.Color is the color type used throughout WPF. This type however is not part of .NET Standard, which uses System.Drawing.Color instead.

It would be very useful that there's an implicit conversion between these two types, so that we can use either to bind in XAML or parse into for instance a color brush etc, so we can reuse these properties for various object models across multiple platforms.

Example:

public class MyViewModel
{
    public System.Drawing.Color Color { get; set; }
}
 <Grid>
   <Grid.DataContext>
        <local:MyViewModel />
   </Grid.DataContext>
   <Ellipse Width="40" Height="40" Fill="{Binding Color}" />
</Grid>

This currently produces a binding error like this:

System.Windows.Data Error: 1 : Cannot create default converter to perform 'one-way' conversions between types 'System.Drawing.Color' and 'System.Windows.Media.Brush'. Consider using Converter property of Binding. BindingExpression:Path=Color; DataItem='MyViewModel' (HashCode=64844482); target element is 'Ellipse' (Name=''); target property is 'Fill' (type 'Brush')
System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='Color [Red]' BindingExpression:Path=Color; DataItem='MyViewModel' (HashCode=64844482); target element is 'Ellipse' (Name=''); target property is 'Fill' (type 'Brush')

I added something similar to Xamarin.Forms as well https://github.com/xamarin/Xamarin.Forms/pull/1359 (Also hoping we can add this to UWP too, so everyone plays nice with .NET Standard).

Implementation suggestion:

namespace System.Windows.Media
{
   public struct Color
   {
        public static implicit operator System.Drawing.Color(Color color) => 
            System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B);

        public static implicit operator Color(System.Drawing.Color color) => 
            FromArgb(color.A, color.R, color.G, color.B);
    }
}
weltkante commented 5 years ago

Does TypeConverter pick up implicit operators? Otherwise you should also update ColorConverter to understand this conversion for this to work in bindings, I think.

dotMorten commented 5 years ago

@weltkante Good point. I think it works for some, but now realizing the above example is not converting to the other color type, but converting to Brush.

miloush commented 5 years ago

The semantics of implicit operator is to provide a conversion where no loss of data occurs.

WPF color is not just RGBA values, it has a color context (profile) and distinguishes sRGB from scRGB. Should there be type conversion operators, it most definitely should not be an implicit one from WPF color to WinForms color.

However, the WinForms color on the other hand has a concept of known color which includes up-to-date system colors (sort of dynamic resources in WPF and in .NET Standard 2.1 Preview) so I would argue this shouldn't be an implicit conversion either.

miloush commented 5 years ago

I am also not very convinced by the cross-platform model argument, it seems that you would also need brushes, pens, points, fonts etc. to be interchangeable, not just colors, so basically unifying the two platforms...

dotMorten commented 5 years ago

I am also not very convinced by the cross-platform model argument, it seems that you would also need brushes, pens, points, fonts etc. to be interchangeable, not just colors, so basically unifying the two platforms...

I have real-world experience behind arguing this is needed. Color goes way beyond pens etc. They are exceptionally useful in view model classes, defining various types of documents, working with raw pixel data etc.

AhmadKelany commented 4 years ago

I am also not very convinced by the cross-platform model argument, it seems that you would also need brushes, pens, points, fonts etc. to be interchangeable, not just colors, so basically unifying the two platforms...

I have real-world experience behind arguing this is needed. Color goes way beyond pens etc. They are exceptionally useful in view model classes, defining various types of documents, working with raw pixel data etc.

I totally agree from experience in many projects.

miloush commented 4 years ago

Clearly the two platforms use two different color structures that don't have one-to-one mapping between them.

An easy solution would be to create your own structure that is intersection of the two. You could use it in any other platform too, not just WPF, and you can then provide any implicit conversion operators and type converters you need, so that it works with binding too.

suchja commented 1 year ago

I just came across this issue, because in applicationSettings it's only possible to store System.Drawing.Color. Thus binding against needs additional conversion.

This would make WPF so much more convenient!!!

miloush commented 1 year ago

@suchja that is unrelated to this issue. In fact, System.Windows.Media.Color, as many other types, are perfectly fine in application settings and the UI lets you use them in .NET Framework:

If you don't see an option to browse for a type (e.g. for the new SDK projects), file a Visual Studio feedback.

suchja commented 1 year ago

@miloush Yes, you are right. After some searching I just figured this out. Unfortunately the Settings-Designer does not show the color as it does for a System.Drawing.Color. However, that is unrelated to this issue as well.

Btw: Thanks for the immediate and very good response!!!